Unity可视化工具链基础

前言

本文主要讲解unity中的部分可视化调试与编辑器工具,主要是面向想要做工具链的程序,较为基础,后续如果想要进阶,可以自行学习Unity的UIToolkit与GraphView

基础

Gizmos

Gizmos是在Scene界面用于辅助画图的工具,一般情况下,我们可以用它绘制范围(比如攻击范围,敌人仇恨范围等);

它的使用也很简单,在Mono脚本中有两个方法:OnDrawGizmos与OnDrawGizmosSelected,前者会始终在Scene界面绘制,而后者只有你选中挂载该脚本的物体时才会绘制,一般的绘制流程如下:

挑选喜欢的颜色->选中对应的图形与范围->结束

请注意,范围是你自己设置的,并不能像UE的轨道检测一样自动绘制范围大小

复制代码
 public class MyGizmos : MonoBehaviour
 {
     public float attackRange = 5f;
     public float viewAngle = 60f;
     public Transform target;

     // 始终显示(选中不选中都画)
     void OnDrawGizmos()
     {
         // 设置颜色
         Gizmos.color = Color.yellow;

         // 画线
         Gizmos.DrawLine(transform.position, transform.position + Vector3.up * 2);

         // 画立方体
         Gizmos.DrawWireCube(transform.position + Vector3.up, Vector3.one);
     }

     // 只在选中时显示
     void OnDrawGizmosSelected()
     {
         // 攻击范围 - 红色球体
         Gizmos.color = new Color(1, 0, 0, 0.3f);
         Gizmos.DrawSphere(transform.position, attackRange);

         Gizmos.color = Color.red;
         Gizmos.DrawWireSphere(transform.position, attackRange);

         // 视野扇形(用线模拟)
         if (target != null)
         {
             Gizmos.color = Color.cyan;
             Gizmos.DrawLine(transform.position, target.position);
         }
     }
 }

Inspector

检查器是我们平时打交道比较多的,当然我们可以利用一些特性将部分字段显示出来

  1. SerializeField\] :序列化字段,顾名思义就是将字段序列化,使其显示在检查器面板上,注意,私有字段也能序列化,属性不能序列化

  2. Tooltip("")\]:放在字段上,用于在检查器介绍该字段的功能,需要你把鼠标放到对应的字段上

  3. HideInInspector\]:将该字段在检查器中隐藏

以下是一个例子,相信看过之后你就能明白这些标签的作用

复制代码
public class Test1 : MonoBehaviour
{
    public int Value1;//public 变量默认会序列化
    protected int Value2;
    private int Value3;

    public int A_mode1;
    public int A_mode2;
    public int B_mode1;//不同模块不会区分
    public int B_mode2;

    public string Tool;
    public string MyName;
}
复制代码
public class Test2 : MonoBehaviour
{
    [HideInInspector]
    public int Value1;//public 变量默认会序列化
    [SerializeField]
    protected int Value2;
    [SerializeField]
    private int Value3;
    [Header("A模块")]
    public int A_mode1;
    public int A_mode2;
    [Header("B模块")]
    public int B_mode1;//不同模块不会区分
    public int B_mode2;
    [Tooltip("这是一个工具")]
    public string Tool;
    [TextArea(5, 5)]
    public string MyName;
}

EditorWindow

我们在Unity中能看到各种各样的窗口,它们都继承自EditorWindow类,我们同样能自己写出这样的窗口。首先需要注意的:脚本放在Assets文件夹的Editor文件夹(没有就新建)中,并引入UnityEditor命名空间

以下是一个例子,我们绕着这个例子处理

复制代码
public class NativeWindow :EditorWindow
{
	//这是核心打开方式,你可以在编辑器的对应目录下打开对应的窗口了
    [MenuItem("Tools/EditorWindows/原生窗口")]
    static void Open() => GetWindow<NativeWindow>("原生").Show();

    string playerName = "Player";//窗口字段,可通过输入框修改其值
    int level = 1;
    float hp = 100f;
    bool isActive = true;
    GameObject test;

    void OnGUI()
    {
        // 1. Label - 纯文本显示
        GUILayout.Label("=== 基础信息 ===", EditorStyles.boldLabel);
        GUILayout.Label("这是一个普通文本标签");

        // 2. 输入框
        playerName = EditorGUILayout.TextField("玩家名称", playerName);
        level = EditorGUILayout.IntField("等级", level);
        hp = EditorGUILayout.FloatField("血量", hp);
		test = (GameObject)EditorGUILayout.ObjectField("测试对象", test, typeof(GameObject), true);
        // 3. Slider - 滑条
        hp = EditorGUILayout.Slider("血量滑条", hp, 0f, 200f);

        GUILayout.Space(20);  // 留空

        // 4. 水平布局
        GUILayout.Label("操作按钮:", EditorStyles.boldLabel);
        GUILayout.BeginHorizontal();//有开始就要有结束

        if (GUILayout.Button("打印你好", GUILayout.Height(30)))
        {
        		Debug.Log("你好");
        }

        if (GUILayout.Button("打印你坏", GUILayout.Height(30)))
        {
        		Debug.Log("你坏");
        }

        GUILayout.EndHorizontal();

        // 5. 垂直布局
        GUILayout.Space(10);
        GUILayout.BeginVertical("box");  // 带边框的垂直组

        GUILayout.Label("高级设置:");

        GUILayout.BeginHorizontal();
        GUILayout.Label("是否激活:", GUILayout.Width(60));
        isActive = EditorGUILayout.Toggle(isActive);//bool变量用toggle框
        GUILayout.EndHorizontal();

        GUILayout.EndVertical();

        GUILayout.Space(10);
    }
}

编辑器窗口使用流程如下:该窗口类有一些成员变量(通常是bool,int,float,string,GameObject)等,在OnGUI函数中画出输入框或者滑条等,设置完这些值再通过 if (GUILayout.Button("按钮名", GUILayout.Height(30)))绘制按钮并判断是否按下来调用方法,需要注意OnGUI()中的各种绘制的方式。

一般情况下,我们可以创建以下的窗口:

  1. 关卡编辑器窗口:一般用于批量在场景中生成或销毁预制体,值得注意的是此时生成需要用PrefabUtility.InstantiatePrefab()之后再Undo.RegisterCreatedObjectUndo(go, "名称");销毁时用Undo.DestroyObjectImmediate();因为此时不是运行时
  2. 修改Asset中的资产,这里需要了解AssetDatabase和GUID,不再赘述
  3. 运行时的编辑器,在游戏运行时动态直接修改玩家的属性,用FindObjectOfType获取对应Mono组件即可,也可以获取场景信息,场景中的敌人数量等

附加内容Odin

Odin插件是一个编辑器扩展插件,里面有一些好用的特性,可以在原有的编辑器基础上扩展,这里简单介绍一下:

常用:

  1. LabelText("")\]:用于将字段在检查器中显示括号中的名字

  2. TableList\]:将列表中的内容按表格展开

  3. Button("")\]:放在方法上,会自动在检查器上创建按钮,按下后即可调用,按钮大小和颜色都可以自定义

  4. ShowIf("")\]\[EnableIf("")\]\[HideIf("")\]:这三个是一套,括号中可以放布尔方法的方法名或布尔字段的字段名,满足条件才会显示或隐藏

复制代码
public class MyToolWindow :OdinEditorWindow//注意这里继承自OdinEditorWindow
{
    [MenuItem("Tools/Windows/测试")]
    static void Open()=>GetWindow<MyToolWindow>().Show();

    [BoxGroup("设置")]//上面提到的特性这里也可以用
    public string PlayerName;
    [BoxGroup("设置"), MinMaxSlider(0, 100)]
    public Vector2Int HpRange;

    [Button("生成"),GUIColor(0.2f,0.8f,0.2f)]
    void Generate()
    {
        Debug.Log("生成玩家");
    }
}

结语

由于GraphView过于繁杂,笔者对其不感兴趣,请读者自行学习,它的作用是利用EditorWindow创建出节点编辑器,比如ShaderGraph,技能树,对话系统,行为树与状态机等,这里不再赘述

相关推荐
云上空13 小时前
腾讯云使用对象存储托管并分享WebGL小游戏(unity3d)(需要域名)
unity·腾讯云·webgl·游戏开发·对象存储·网页托管
小贺儿开发15 小时前
Unity3D VR党史主题展馆
unity·人机交互·vr·urp·展馆·党史
TopGames15 小时前
Unity实现10万人同屏动态避障和导航寻路系统 支持3D地形
unity·性能优化·游戏引擎
在路上看风景18 小时前
01. GUIContent
unity
托洛夫斯基扎沙耶19 小时前
Unity中状态机与行为树的简单实现
unity·游戏引擎
速易达网络19 小时前
速易达画图工具:轻量全能,让创意跃然“屏”上
编辑器
山峰哥20 小时前
SQL优化实战:从索引策略到查询性能提升的深度解析
开发语言·数据库·sql·性能优化·编辑器
TrudgeCarrot1 天前
unity打包使用SPB管线出现 DontSava错误解决
unity·游戏引擎·dontsave
3D霸霸1 天前
unity 创建URP新场景
unity·游戏引擎
程序员ken1 天前
献给自己的一款个人管理的桌面软件(二)
python·c#·编辑器