游戏开发小结——我在 Unity 中制作了自定义编辑器
在开发自己的游戏时,在 Unity 中制作自定义编辑器脚本可以改变游戏规则。根据您的项目需求量身定制的自定义检查器、窗口和工具可提高效率和精度,使开发过程更加顺畅和愉快。
以下是在 Unity 中编写自定义编辑器的一些好处
-
定制工作流程:设计自定义编辑器可以让您根据游戏需求简化工作流程。您可以创建能够简化复杂任务、加快开发速度并减少错误的工具。
-
提高生产力:自定义编辑器可自动执行重复性任务,从而在资产管理、关卡设计或游戏创建期间节省宝贵的时间。这种效率提升使您能够更加专注于实际的游戏开发。
-
用户友好的界面:根据您的项目定制检查器和窗口可确保更直观和用户友好的界面。它可以更轻松地导航和操作游戏元素,使您和您的团队受益。
-
精确控制:通过自定义检查器微调属性和设置,可以精确控制游戏元素。这种级别的细节可确保您的游戏完全按照预期运行,从而最大限度地减少意外问题。
-
增强创造力:通过消除默认 Unity 工具的限制,自定义编辑器鼓励实验和创新。您可以探索实现功能和机制的新方法,培养创造力。
让我们一起构建一个示例
让我们首先定义我们的目标:我们有一个“玩家”类,负责与健康相关的属性。
首先,我们的目标是确保健康属性保持在指定范围内,限制在最小值和最大值之间。该属性也将是一个序列化字段,允许在 Unity Inspector 中访问和修改它。
接下来,我们将首先创建一个新的编辑器类并将其放置在“Editor”文件夹中。此操作指示 Unity 从最终构建中排除该类,从而防止编译期间出现任何潜在错误。
[UnityEditor.CustomEditor(typeof(Player),true)]
public class PlayerEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
serializedObject.Update();
GUI.enabled = false;
EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Script"));
GUI.enabled = true;
serializedObject.ApplyModifiedProperties();
}
}
我们将生成一个名为“PlayerEditor”的新类,继承自“UnityEngine.Editor”。后续步骤涉及将此类标记为“Player”类的自定义编辑器。我们通过使用“CustomEditor”属性来实现这一点,指定“Player”作为目标。或者,我们可以传递一个布尔值作为第二个参数,允许在此编辑器中管理从“Player”继承的其他类。
在“OnInspectorGUI”方法中,我们可以管理与类相关的各个方面。通过访问 Editor 类中的“serializedObject”字段,我们可以获得对所有字段的引用。
在深入研究之前,让我们通过配置编辑器以包含“脚本”字段并禁用它来确保一致性。
我们首先调用“serializedObject.Update()”,这是一个关键方法,可确保刷新对象并为任何后续调整做好准备。
完成修改后,我们调用“serializedObject.ApplyModifiedProperties()”。该函数刷新对象的值并将其标记为潜在的撤消事件。
在这些功能之间,我们有机会设计我们的自定义字段。我们首先使用“serializedObject.FindProperty”获取对字段的引用,并提供每个字段的名称。检索后,我们继续使用“EditorGUILayout.PropertyField”绘制这些字段,利用之前存储的字段引用。
完成后,代码结构如下所示:
public override void OnInspectorGUI()
{
serializedObject.Update();
GUI.enabled = false;
EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Script"));
GUI.enabled = true;
var minHealthProp = serializedObject.FindProperty("minHealth");
var maxHealthProp = serializedObject.FindProperty("maxHealth");
var healthProp = serializedObject.FindProperty("health");
EditorGUILayout.PropertyField(minHealthProp);
EditorGUILayout.PropertyField(maxHealthProp);
EditorGUILayout.PropertyField(healthProp);
serializedObject.ApplyModifiedProperties();
}
“现在,恢复了初始状态,我们已经有效地从头开始重建了inspector。现在,我们准备合并自定义功能,例如代表健康health状况的滑块,同时确保其遵守定义的最小和最大健康值health 。
使用“EditorGUILayout.IntSlider”绘制滑块非常简单。通过指定滑块的标签、当前值、最小值和最大值,我们可以获得更新的值。获得这个新值后,只有当 GUI 确实发生变化时,我们才会谨慎地将其分配给健康字段。在分配过程中,我们确保将值限制在定义的最小和最大健康值之间。
添加一个有趣的触摸,我们可以轻松地引入一个按钮来随机化当前的健康状况。利用“GUILayout.Button”,该函数的结果会发出按钮是否被按下的信号。按下按钮后,我们实现自定义逻辑 - 在本例中,是随机化健康字段。
if (GUILayout.Button("Randomize health"))
{
var randomHealth = Random.Range(minHealthProp.intValue, maxHealthProp.intValue);
healthProp.intValue = randomHealth;
}
这是inspector的最终外观
这是编辑器的最终代码
using UnityEditor;
using UnityEngine;
namespace OM.Editor
{
[UnityEditor.CustomEditor(typeof(Player),true)]
public class PlayerEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
serializedObject.Update();
GUI.enabled = false;
EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Script"));
GUI.enabled = true;
var minHealthProp = serializedObject.FindProperty("minHealth");
var maxHealthProp = serializedObject.FindProperty("maxHealth");
var healthProp = serializedObject.FindProperty("health");
EditorGUILayout.PropertyField(minHealthProp);
EditorGUILayout.PropertyField(maxHealthProp);
EditorGUILayout.PropertyField(healthProp);
var newHealthValue = EditorGUILayout.IntSlider("Health", healthProp.intValue, minHealthProp.intValue, maxHealthProp.intValue);
if (GUI.changed)
{
healthProp.intValue = Mathf.Clamp(newHealthValue, minHealthProp.intValue, maxHealthProp.intValue);
}
if (GUILayout.Button("Randomize health"))
{
var randomHealth = Random.Range(minHealthProp.intValue, maxHealthProp.intValue);
healthProp.intValue = randomHealth;
}
serializedObject.ApplyModifiedProperties();
}
}
}