Unity | 编辑器开发:Inspector扩展+独立窗口
在Unity开发中我们还可以使用自定义窗口进行编辑器扩展。unity建议将自定义的插件启动项置于Tools目录下。Unity | 编辑器开发-CSDN博客//unity建议将自定义的插件启动项置于Tools目录中//在这个静态方法中执行窗口的创建//打开MyWindows窗口时,会调用Awake方法//事件委托,它会在 Scene 视图的每一帧 GUI 渲染时被调用。//场景视图GUI取消绑定vo
目录
(2.1)EditorGUILayout.PropertyField
(2.2)Update()与ApplyModifiedProperties()
编辑器工具大致可分为脚本Inspector的扩展和独立窗口两大部分,这两大部分又涉及SceneView绘制和Preview窗口绘制等。
一、Inspector行为面板扩展
1.创建一个脚本
Enemy_Type1类有三个属性:血量、速度、攻击力,并有默认的初始值。
using UnityEngine;
public class Enemy_Type1 : MonoBehaviour
{
public int hp = 100; //血量
public float speed = 300; //速度
public int atk = 10; //攻击力
}
2.创建行为面板扩展的Editor脚本
Editor脚本实现CustomEditor特性,并重写OnInspectorGUI方法。通过OnInspectorGUI方法的重写,我们可以为其自定义行为面板属性内容,比如增加几个按钮预设,方便初始化不同类型的参数。
- CustomEditor是Unity编辑器中的一个特性,允许开发者为特定组件创建自定义的检视器界面,替代默认的Inspector面板。
[CustomEditor(typeof(目标组件类型))]
特性关联目标组件。- OnInspectorGUI是CustomEditor类中的一个关键方法,负责绘制自定义的UI界面。每当Inspector面板需要刷新时,Unity会调用这个方法,所以在这里添加GUI元素可以实时更新显示。
(1)重写面板绘制方法
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Enemy_Type1))] //这里链接到MonoBehaviour脚本
public class Enemy_Type1Inspector : Editor
{
/// <summary>
/// 重写面板绘制方法:增加几个按钮预设,方便初始化不同类型的参数
/// </summary>
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
//获取绑定的MonoBehaviour脚本对象
var concertTarget = base.target as Enemy_Type1;
if (GUILayout.Button("preset1")) //角色属性预设1
{
concertTarget.hp = 100;
concertTarget.speed = 600;
concertTarget.atk = 6;
}
if (GUILayout.Button("preset2")) //角色属性预设2
{
concertTarget.hp = 200;
concertTarget.speed = 550;
concertTarget.atk = 4;
}
}
}
(2)获取序列化字段,并进行名称修改
(2.1)EditorGUILayout.PropertyField
通过EditorGUILayout.PropertyField
可将SerializedProperty
序列化属性转化为Inspector面板的交互控件(如滑动条、勾选框等),无需手动编写不同数据类型的UI逻辑
EditorGUILayout.PropertyField(serializedObject.FindProperty("rotationSpeed"));
此代码会自动根据rotationSpeed
字段的类型(如float
或int
)生成对应的控件,在Inspector面板进行展示。
(2.2)Update()与ApplyModifiedProperties()
- Update():从目标对象读取最新属性值到SerializedObject中,保证数据同步。
- ApplyModifiedProperties():将用户在Inspector的修改回写至实际对象,自动处理撤销操作和多对象批量修改。
(2.3)FindProperty方法
通过字段名字符串获取SerializedProperty对象(如_previewAngle),需确保字段名称与脚本中的序列化字段完全匹配。
public override void OnInspectorGUI()
{
serializedObject.Update(); //首先更新序列化对象
//生命值,序列化字段对象
var hpProp = serializedObject.FindProperty("hp");
//速度,序列化字段对象
var speedProp = serializedObject.FindProperty("speed");
//攻击力,序列化字段对象
var atkProp = serializedObject.FindProperty("atk");
using (var change = new EditorGUI.ChangeCheckScope())//监测GUI内容改变
{
EditorGUILayout.PropertyField(hpProp, new GUIContent("Enemy hp"));
EditorGUILayout.PropertyField(speedProp, new GUIContent("Enemy speed"));
EditorGUILayout.PropertyField(atkProp, new GUIContent("Enemy atk"));
//直接进行序列化字段绘制
if (GUILayout.Button("preset1")) //预设1按钮
{
hpProp.intValue = 100;
speedProp.floatValue = 600;
atkProp.intValue = 6;
}
if (GUILayout.Button("preset2")) //预设2按钮
{
hpProp.intValue = 200;
speedProp.floatValue = 550;
atkProp.intValue = 4;
}
if (change.changed) //如果改变则应用修改
{
serializedObject.ApplyModifiedProperties();
}
}
}
二、使用EditWindow自定义窗口
在Unity开发中我们还可以使用自定义窗口进行编辑器扩展。unity建议将自定义的插件启动项置于Tools目录下。附上一篇关于编辑器开发的文章:Unity | 编辑器开发-CSDN博客
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class MyWindows : EditorWindow
{
//unity建议将自定义的插件启动项置于Tools目录中
[MenuItem("Tools/Battle Debuger")]
static void Setup()
{
//在这个静态方法中执行窗口的创建
GetWindow<MyWindows>();
}
void Awake()
{
//打开MyWindows窗口时,会调用Awake方法
Debug.Log("Awake");
//事件委托,它会在 Scene 视图的每一帧 GUI 渲染时被调用。
SceneView.duringSceneGui += OnSceneGUIDelegateBind;
}
void OnDestroy()
{
//场景视图GUI取消绑定
SceneView.duringSceneGui -= OnSceneGUIDelegateBind;
}
void OnGUI() //绘制窗口的GUI内容
{
if (GUILayout.Button("Generate Enemy_Type1"))
{
//省略其他代码
}
if (GUILayout.Button("Generate Enemy_Type1 x10"))
{
//省略其他代码
}
if (GUILayout.Button("Killed All Enemy"))
{
//省略其他代码
}
}
void OnSceneGUIDelegateBind(SceneView sceneView)
{
Debug.Log("OnSceneGUIDelegateBind");
var enemies = GetEnemies();
for (int i = 0; i < enemies.Length; i++)
{
var enemy = enemies[i];
//Unity的Handles类提供的绘图API,用于在Scene视图中绘制线框等图形,并且这些图形只在编辑器下可见,不影响运行时。
Handles.DrawWireCube(enemy.Position, new Vector3(0.5f, 1f, 0.5f));
}//将敌人以方块绘制出来
}
struct EnemyInfo { public Vector3 Position { get; set; } } //调试数据
EnemyInfo[] GetEnemies()
{
return new EnemyInfo[] {
new EnemyInfo()
{
Position = new Vector3(0f, 0f, 0f)
},
new EnemyInfo() {
Position = new Vector3(1.5f, 0f, 0f)
}
};
}
}
——本文总结自微信读书《Unity3D动作游戏开发实战》
更多推荐
所有评论(0)