unity初级——Inspector检视器面板开发

这篇具有很好参考价值的文章主要介绍了unity初级——Inspector检视器面板开发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、背景知识:

1、C#特性:

2、Unity中特殊目录:

3、*注意:

二、编辑器检视面板扩展属性

二、通过Editor脚本扩展组件(检视器外挂式开发)

三、检视器窗口开发

四、完成点击生成方块的工具


一、背景知识:

1、C#特性:

[System.Serializable]

2、Unity中特殊目录:

Resources:存储资源目录。

Plugins:需要跨语言条用的逻辑代码目录,三方插件,sdk等。

StreamingAssets:只读,存储更游戏包的资源目录,热更新资源目录。

Editor:编辑器目录,存放于编辑器相关的资源和逻辑代码。

3、*注意:

1、多目录是可以同时存在的。

2、在打包的时候不会生成到项目中

3、UnityEditor命名空间不要出现在游戏发布的代码中

二、编辑器检视面板扩展属性

//隐藏公共成员变量,防止Inspector的值影响到它
//同时保证脚本中变量的可访问度
[HideInInspector]

//私有变量,检视面板可见
//Unity会将对象进行序列化存储,所以即使是私有的,那么标记为可序列化后,就会显示,共有默认是可序列化的
[SerializeField]

//初始化 System.SerializableAttribute 类的新实例。
//表示类可以被序列化,此类不能被继承
[Serializable]

//给数值设定范围(最小min,最大max)
[Range(min, max)]

//添加变量悬浮提示文字
//一个成员变量可以添加多个特性
[Tooltip("这是一个提示")]

//指定输入框,拥有line行
[Multiline(int line)]

//默认显示5行,最多显示10行内容,再多用滚动条控制显示区域
[TextArea(5, 10)]

//给一个成员变量添加右键菜单
//第一个参数是菜单的名称
//第二个参数是右键点击的回调函数
[ContextMenuItem(string name, string function)]

//给小齿轮增加一个回调函数
[ContextMenu(string itemName)]

//使生命周期函数,在编辑器状态下可以执行,游戏中也可以正常使用
//Update()在场景中对象发生变化或项目组织发生变化时会在编辑器下执行
[ExecuteInEditMode]

//当前组件依赖于盒子碰撞体
//当前组件挂载在对象上时,被依赖组件会一起被添加上去
//当依赖组件没有被移除时,被依赖组件不能被删除
[RequireComponent(Type requiredComponent)]

//将组件添加到AddComponent下
//第一个参数:分类名/组件名
//第二个参数:列表中显示的顺序
[AddComponentMenu(string menuName,int order)]

//将组件添加到顶部菜单栏下
[MenuItem(string itemName)]

//将当前编辑器扩展脚本和需要扩展的组件,建立关联关系(当前脚本的功能就可以扩展到对应的组件上了)
[CustomEditor(Type inspectedType)]  

二、通过Editor脚本扩展组件(检视器外挂式开发)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;  //步骤1:检视器的扩展开发属于编辑器范畴,所以使用 UnityEditor 命名空间

[CustomEditor(typeof(Player))]  //步骤3:将当前编辑器扩展脚本和需要扩展的组件,建立关联关系(当前脚本的功能就可以扩展到对应的组件上了)
public class PlayerEditor : Editor  //步骤2:继承Editor,使用声明周期函数及成员变量,参考 MonoBehavior
{
    //步骤5:选中或挂载时,需要获取被编辑的组件,只有获取到组件,才能对检视器的显示做处理
    private Player _Player;

    //步骤4:确定,什么时候显示内容在监视器面板中,即使用生命周期函数
    //关联组件被挂载在场景中时,或选中挂载对象时被调用
    private void OnEnable()
    {
        //步骤5:通过父类获取当前选中或挂载的脚本组件
        _Player = target as Player;
        Debug.Log("Enable");
    }

    //关联组件在场景中被移除时,或挂载对象失去焦点时被调用
    private void OnDisable()
    {
        Debug.Log("Disable");
    }

    //已经获得了需要扩展显示的组件,现在需要一种方式修改检视器内部的内容
    //重写OnInspectorGUI,内部可以实现重新绘制检视器内部的内容
    public override void OnInspectorGUI()
    {
        //所有API都是处理检视器
        //实现文字显示
        EditorGUILayout.LabelField("人物相关属性");

        //简单数据类型绘制//

        //使用绘制方法,重新绘制ID字段(获取原始ID,绘制后,再对原始ID赋值)
        _Player.ID = EditorGUILayout.IntField("玩家ID", _Player.ID);

        //文本
        _Player.Name = EditorGUILayout.TextField("玩家名称", _Player.Name);
        //浮点数
        _Player.Atk = EditorGUILayout.FloatField("玩家攻击力", _Player.Atk);
        //布尔
        _Player.isMan = EditorGUILayout.Toggle("是否为男性", _Player.isMan);
        //向量
        _Player.HeadDir = EditorGUILayout.Vector3Field("头部方向", _Player.HeadDir);
        //颜色
        _Player.Hair = EditorGUILayout.ColorField("头发颜色", _Player.Hair);

        对象数据类型绘制-绘制对象类型//
        //参数1:标题
        //参数2:原始组件的值
        //参数3:成员变量的类型
        //参数4:是否可以将场景中的对象拖给这个成员变量
        _Player.Weapon = EditorGUILayout.ObjectField("持有武器", _Player.Weapon, typeof(GameObject), true) as GameObject;
        //纹理
        _Player.Cloth = EditorGUILayout.ObjectField("衣服材质贴图", _Player.Cloth, typeof(Texture), false) as Texture;

        枚举数据类型绘制
        //整数转枚举
        //int id = 0;
        //PLAYER_PROFESSION p = (PLAYER_PROFESSION)id;

        //单选枚举(标题, 组件上的原始值)
        _Player.Profession = (PLAYER_PROFESSION)EditorGUILayout.EnumPopup("玩家职业", _Player.Profession);

        //多选枚举(标题, 组件上的原始值)
        _Player.Talent = (PLAYER_TALENT)EditorGUILayout.EnumFlagsField("玩家天赋", _Player.Talent);

        终极数据类型绘制
        //更新可序列化数据
        serializedObject.Update();
        //通过成员变量名找到组件上的成员变量
        SerializedProperty sp = serializedObject.FindProperty("Items");
        //可序列化数据绘制(取到的数据,标题,是否将所有获得的序列化数据显示出来)
        EditorGUILayout.PropertyField(sp, new GUIContent("道具信息"), true);
        //将修改的数据,写入到可序列化的原始数据中
        serializedObject.ApplyModifiedProperties();

        滑动条绘制
        //滑动条显示(1.标题,2.原始变量,最小值,最大值)
        _Player.Atk = EditorGUILayout.Slider(new GUIContent("玩家攻击力"), _Player.Atk, 0, 100);

        if(_Player.Atk > 80)
        {
            //显示消息框(红色)
            EditorGUILayout.HelpBox("攻击力太高了", MessageType.Error);
        }

        if(_Player.Atk < 20)
        {
            //显示消息框(黄色)
            EditorGUILayout.HelpBox("攻击力太低了", MessageType.Warning);
        }

        //按钮显示和元素排列
        //(按钮是否被按下)显示按钮(按钮名称)
        GUILayout.Button("来个按钮");
        GUILayout.Button("来个按钮");

        //根据按钮返回值,判定按钮是否被按下
        if(GUILayout.Button("测试"))
        {
            Debug.Log("测试");
        }

        //开始横向排列绘制
        EditorGUILayout.BeginHorizontal();

        if (GUILayout.Button("检查"))
        {
            Debug.Log("检查");
        }

        if (GUILayout.Button("排查"))
        {
            Debug.Log("排查");
        }

        //结束横向排列绘制
        EditorGUILayout.EndHorizontal();
    }
}

三、检视器窗口开发

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;  //使用编辑器命名空间

//继承EditorWindow,需要使用内部声明周期函数和成员变量
public class TestWindow : EditorWindow
{
    [MenuItem("工具/创建窗口")]
    static void OpenWin()
    {
        //创建窗口
        //泛型:窗口类对象类型
        //是否为工具窗口
        //窗口的标签名
        //创建窗口后,是否马上让窗口获得焦点
        TestWindow window = GetWindow<TestWindow>(false, "测试窗口", true);
        //给窗口最小尺寸赋值
        window.minSize = new Vector2(400, 300);
        //给窗口最大尺寸赋值
        window.maxSize = new Vector2(800, 600);
    }

    //开启窗口时,被调用
    private void OnEnable()
    {
        Debug.Log("窗口Enable");
    }

    //窗口关闭时,被调用
    private void OnDisable()
    {
        Debug.Log("窗口Disable");
    }

    //只要窗口存在时,Update每帧都会被调用
    public void Update()
    {
        //Debug.Log("窗口Update");
    }

    //场景内部结构有变化时,回调生命周期函数(变一次调一次)
    private void OnHierarchyChange()
    {
        Debug.Log("窗口Hierarchy");
    }

    //项目有变化时,回调生命周期函数(变一次调一次)
    private void OnProjectChange()
    {
        Debug.Log("窗口Project");
    }

    //当选中物体发生变化时调用
    private void OnSelectionChange()
    {
        //获得当前选中的GameObject名称
        Debug.Log("窗口SelectionChange: " + Selection.activeGameObject.name);
    }

    //窗口开启时,每帧会调用 OnGUI 绘制窗口内容
    private void OnGUI()
    {
        if(GUILayout.Button("测试"))
        {
            ShowNotification(new GUIContent("测试窗口按钮"));
        }
    }
}

四、完成点击生成方块的工具

1、Editor类:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class NodeWindow : EditorWindow
{
    static NodeWindow window;

    static GameObject nodeManager;

    public static void OpenWindow(GameObject manager)
    {
        nodeManager = manager;
        //真正开启了一个窗口
        window = EditorWindow.GetWindow<NodeWindow>();
    }

    void Update()
    {
        //通过窗口的Update,每帧执行一次,当前被选中的对象为板子
        Selection.activeGameObject = nodeManager;
    }

    public static void CloseWindow()
    {
        window.Close();
    }
}

//外挂式关联NodeManager
[CustomEditor(typeof(NodeManager))]
public class NodeManagerEditor : Editor
{

    NodeManager manager;

    bool isEditor = false;//是否是编辑的状态

    //当选中带有NodeManager组件对象的时候,获得组件
    void OnEnable()
    {
        manager = (NodeManager)target;
        Debug.Log("manager:" + manager);
    }

    //绘制组件的生命周期函数
    public override void OnInspectorGUI()
    {
        //通过终极的数据获取方法,显示列表中的数据
        serializedObject.Update();
        SerializedProperty nodes = serializedObject.FindProperty("nodes");
        EditorGUILayout.PropertyField(nodes, new GUIContent("路径"), true);
        serializedObject.ApplyModifiedProperties();

        //开始编辑的开关
        if (!isEditor && GUILayout.Button("开始编辑"))
        {
            NodeWindow.OpenWindow(manager.gameObject);//调用打开界面的方法
            isEditor = true;//改变状态变成编辑模式
        }
        //结束编辑的开关
        else if (isEditor && GUILayout.Button("结束编辑"))
        {
            NodeWindow.CloseWindow();//调用关闭界面的方法
            isEditor = false;//改变状态变成非编辑模式
        }

        //删除按钮
        if (GUILayout.Button("删除最后一个节点"))
        {
            RemoveAtLast();
        }
        //删除所有按钮
        else if (GUILayout.Button("删除所有节点"))
        {
            RemoveAll();
        }
    }

    RaycastHit hit;
   
    //有点类似前期Update函数,发送射线
    //当选中关联的脚本挂载的物体
    //当鼠标在Scene视图下发生变化时,执行该方法,比如鼠标移动,比如鼠标的点击
    void OnSceneGUI()
    {

        if (!isEditor)//非编辑状态下不能生成路点
        {
            return;
        }

        //当鼠标按下左键时发射一条射线 
        //非运行时,使用Event类
        //Event.current.button 判断鼠标是哪个按键的(0是鼠标左键)
        //Event.current.type 判断鼠标的事件方式的(鼠标按下)
        if (Event.current.button == 0 && Event.current.type == EventType.MouseDown)
        {
            //从鼠标的位置需要发射射线了
            //因为是从Scene视图下发射射线,跟场景中的摄像机并没有关系,所以不能使用相机发射射线的方法
            //从编辑器GUI中的一个点向世界定义一条射线, 参数一般都是鼠标的坐标
            Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
            if (Physics.Raycast(ray, out hit, 100, 1 << 9))
            {
                //需要在检测到的点实例化,路点
                InstancePathNode(hit.point + Vector3.up * 0.1f);
            }

        }
    }

    /// <summary>
    /// 生成节点
    /// </summary>
    /// <param name="position"></param>
    void InstancePathNode(Vector3 position)
    {
        //点预制体
        GameObject prefab = Resources.Load<GameObject>("PathNode");
        //点对象,生成到Plane的子物体下
        GameObject pathNode= Instantiate<GameObject>(prefab, position, Quaternion.identity, manager.transform);
        //把生成的路点添加到列表里
        manager.nodes.Add(pathNode);
    }

    /// <summary>
    /// 删除最后一个节点
    /// </summary>
    void RemoveAtLast()
    {
        //保证有节点才能删节点
        if (manager.nodes.Count > 0)
        {
            //从场景中删除游戏物体
            DestroyImmediate(manager.nodes[manager.nodes.Count - 1]);
            //把该节点从列表中移除
            manager.nodes.RemoveAt(manager.nodes.Count - 1);
        }

    }


    /// <summary>
    /// 删除所有的节点
    /// </summary>
    void RemoveAll()
    {
        ///遍历删除所有的节点物体
        for (int i = 0; i < manager.nodes.Count; i++)
        {
            if (manager.nodes[i] != null)
            {
                DestroyImmediate(manager.nodes[i]);
            }
        }

        manager.nodes.Clear();//清空列表
    }


}

2、脚本类:文章来源地址https://www.toymoban.com/news/detail-702906.html

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]//在编辑模式下可以执行一些生命周期函数
public class NodeManager : MonoBehaviour {

    //存储了所有编辑器下点击生成的点,并使用预制体显示
    public List<GameObject> nodes;

	// Use this for initialization
	void Start () {
		
	}

	void Update () {
        if (nodes != null&&nodes.Count>1)
        {
            for (int i = 0; i < nodes.Count - 1; i++)
            {
                Debug.DrawLine(nodes[i].transform.position,
                    nodes[i + 1].transform.position,
                    Color.red,
                    Time.deltaTime);
            }
        }
        
	}
}

到了这里,关于unity初级——Inspector检视器面板开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity3D日常开发】Unity3D中实现单例模式详解

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 大家好,我是佛系工程师 ☆恬静的小魔龙☆ ,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 首先,说一下,什么是 单例模式(Singleton) 。 单例模式是设计模式中常见的一种设计模式,目的是为了

    2024年02月02日
    浏览(62)
  • 【Unity3D日常开发】Unity3D中实现不同脚本之间的执行顺序控制

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 大家好,我是佛系工程师 ☆恬静的小魔龙☆ ,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 首先,来了解一下事件函数的执行顺序,下图是官方给的脚本中事件函数的执行顺序: 众所周知,U

    2024年02月02日
    浏览(52)
  • 【Unity3D编辑器开发】Unity3D中实现Transform快速复制粘贴【非常实用】

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 大家好,我是佛系工程师 ☆恬静的小魔龙☆ ,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 在开发中,常常会遇到频繁复制粘贴物体的坐标、旋转、缩放的操作。 使用Unity自带的组件复制粘贴比

    2024年02月07日
    浏览(61)
  • Unity读书系列《Unity3D游戏开发》——脚本(一)

    脚本在Unity的重要程度不用多说,她是大部分软件的核心组件。 我们将在此篇文章学习脚本模版及其拓展、脚本的生命周期、脚本的执行顺序、脚本序列化,下一篇为脚本编译与调试。 如下图我们可以在Project视图右键进行脚本创建,除了C#脚本,还有两类脚本;Testing用来做

    2024年04月28日
    浏览(81)
  • Unity读书系列《Unity3D游戏开发》——基础知识

    本篇对应标题书籍的第一章基础知识,也就是unity的基本常识和工作流的说明。 Unity目前用于创建2D和3D游戏、模拟应用程序、可视化体验以及其他虚拟现实(VR)和增强现实(AR)应用,游戏工业两开花。 Unity初版是在2005年发布的,开始时用unity3.X、4.X这样的名称进行版本更新

    2024年01月18日
    浏览(84)
  • Unity3D开发之unity和js通信交互

    官方 方法分享:Unity - 手动:与浏览器脚本的交互 (unity3d.com) 首先需要写一个JS的脚本,主要是调用mergeInto();方法,第一个参数不用变,第二个参数就是JS的方法集合。写完之后将这个文件的后缀改为.jslib,放到Plugins文件夹中  Test  内容: 2.C#(挂在场景 任意物体上) 3.Uni

    2024年02月12日
    浏览(40)
  • Unity3D开发之刚体休眠问题

    我们在开发的时候会遇到这个问题:两个带有刚体和collider的静止物体相互接触,在挂有OnCollisionStay()函数中debug,只有程序刚运行的时候会有二十多个log,之后就再也没有输出。原以为是unity版本bug,后来查询资料发现这是unity的优化机制。 When a Rigidbody moves at a slower speed th

    2024年02月12日
    浏览(41)
  • Unity3D小程序部署与开发

    Unity3D目前已经支持微信小程序开发,目前正处于公测阶段,可以参考文档。这样我们只需要在unity本地开发完,一键导出微信小程序工程发布即可。 小程序开发工具: wechat_devtools_1.05.2204264_x64.exe UnityPlugin小程序插件: minigame.202302151921.unitypackage 在开发之前,我们需要到微信公众

    2024年02月09日
    浏览(43)
  • Unity3D开发之OnPointerClick事件

    OnPointerClick是unity事件系统自带的点击推送事件。继承IPointerClickHandler接口,并在脚本中实现接口,点击挂此脚本的物体系统会调用实现的OnPointerClick函数。 下面说下这个接口的缺陷。当我们要判断是双击物体还是单击物体时,我们要使用PointerEventData里的clickCount。用户双击会

    2024年02月11日
    浏览(45)
  • Unity读书系列《Unity3D游戏开发》——编辑器的结构

    本篇对应标题书籍的第二章编辑器的结构,也就是unity的编辑器的使用及菜单的使用。 当我们制作的软件或游戏需要多人合作时,就会使用git、svn进行版本管理。一般来说只保留Assets、ProjectSettings、Packages这几个文件夹,git会自动生成.git文件,我们添加需要屏蔽的文件夹或后

    2024年01月25日
    浏览(113)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包