一.我们要写编辑器,首先要知道编辑器是什么?
Unity编辑器是游戏开发的基础环境,提供了强大的工具,使开发者能够创建复杂的游戏世界和动态的游戏元素。Unity编辑器通过自定义编辑器扩展,提高了开发效率和创造力。自定义编辑器可以让开发者根据游戏需求简化工作流程,自动执行重复性任务,节省时间,并提高生产力。Unity编辑器的用户界面直观易用,开发者可以轻松地进行场景构建、资源管理、动画制作、光照设置等多种操作。
二.角色编辑器与技能编辑器
1.首先,要想写编辑器,先要在Assets旗下创建一个专门的文件夹,并且命名为Editor,在这个文件夹中创建一个RoleEditor的脚本,并且导入using UnityEditor;的命名空间,将脚本继承的MonoBehaviour换成EditorWindow,其次,我们要想在Unity界面显示出编辑器(Editor),要写[MenuItem("Editor/编辑器名称")]。写这句话的效果图如下:

2.要想显示出编辑器,有一处是特别要注意的,就是要写GetWindow<RoleEditor>("RoleEditor").Show();的这句话的方法一定要用静态,否则无法显示编辑器。写法如下图:

3.编辑器要想选择图片,一定要注意我们的Sprite精灵图是.jpg格式还是.png格式等,因为我这里写的加载图片的路径,Replace用来掐头去尾,不清楚的可以把所有格式全部写出来,或者点击精灵图也可以查看精灵图的格式:
4.最后代码总结:
(1)数据基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DataBase
{
public int id;
public string name = "";
public string iconPath = "";
}
public class RoleData : DataBase
{
public int hp;
public int atk;
public int speed;
public string rolePath = "";
public List<int> skillid = new List<int>();
}
public class SkillData : DataBase
{
public string skillPath = "";
public float dis;
public float range;
public int num = 1;
public List<int> buffid = new List<int>();
}
public class BuffData : DataBase
{
public string buffPath = "";
public string animPath = "";
public int num;
public float value;
}
(2)单例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Singleton<T> where T : class, new()
{
private static T instance;
public static T Instance
{
get
{
if(instance == null)
{
instance = new T();
}
return instance;
}
}
}
(3)管理类
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public class ConfigManager : Singleton<ConfigManager>
{
public const string rolePath = "Json/RolePath";
public const string skillPath = "Json/SkillPath";
public const string buffPath = "Json/BuffPath";
static Dictionary<string, object> dic = new Dictionary<string, object>();
public Dictionary<int, T> GetDic<T>(string path)
{
if(dic.ContainsKey(path))
{
return dic[path] as Dictionary<int, T>;
}
if(File.Exists(Application.dataPath + "/Resources/" + path + ".json"))
{
string json = Resources.Load<TextAsset>(path).text;
Dictionary<int,T> tdic = JsonConvert.DeserializeObject<Dictionary<int,T>>(json);
return tdic;
}
return new Dictionary<int, T>();
}
public T GetData<T>(string path, int id)
{
Dictionary<int, T> tdic = GetDic<T>(path);
return tdic[id];
}
public void Save(string path, object obj)
{
string json = JsonConvert.SerializeObject(obj);
File.WriteAllText(Application.dataPath + "/Resources/" + path + ".json", json);
}
public List<string> GetNames<T>(string path, params string[] str) where T : DataBase
{
List<string> list = new List<string>();
foreach (var item in GetDic<T>(path).Values)
{
list.Add(item.name);
}
foreach (var item in str)
{
list.Add(item);
}
return list;
}
}
(4) 角色编辑器
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class RoleEditor : EditorWindow
{
static Dictionary<int, RoleData> dic;
static List<string> nameArr;
static List<string> skillArr;
[MenuItem("Editor/RoleEditor")]
public static void Init()
{
GetWindow<RoleEditor>("RoleEditor").Show();
dic = ConfigManager.Instance.GetDic<RoleData>(ConfigManager.rolePath);
nameArr = ConfigManager.Instance.GetNames<RoleData>(ConfigManager.rolePath, "创建新角色");
skillArr = ConfigManager.Instance.GetNames<SkillData>(ConfigManager.skillPath);
}
public static int id;
Sprite sprite;
GameObject model;
int skillid;
private void OnGUI()
{
id = EditorGUILayout.Popup("选择", id, nameArr.ToArray());
if(!dic.ContainsKey(id))
{
dic.Add(id, new RoleData());
dic[id].id = id;
}
dic[id].name = EditorGUILayout.TextField("名称:", dic[id].name);
if (dic[id].iconPath.Length > 0)
{
sprite = Resources.Load<Sprite>(dic[id].iconPath);
}
sprite = (Sprite)EditorGUILayout.ObjectField(sprite, typeof(Sprite), false, GUILayout.Width(100), GUILayout.Height(100));
if(sprite != null)
{
string path = AssetDatabase.GetAssetPath(sprite);
path = path.Replace("Assets/Resources/", "");
path = path.Replace(".jpg", "");
path = path.Replace(".png", "");
dic[id].iconPath = path;
}
if (dic[id].rolePath.Length > 0)
{
model = Resources.Load<GameObject>(dic[id].rolePath);
}
model = (GameObject)EditorGUILayout.ObjectField("人物模型:", model, typeof(GameObject), false);
if (model != null)
{
string path = AssetDatabase.GetAssetPath(model);
path = path.Replace("Assets/Resources/", "");
path = path.Replace(".prefab", "");
dic[id].rolePath = path;
}
dic[id].hp = EditorGUILayout.IntField("血量:", dic[id].hp);
dic[id].atk = EditorGUILayout.IntField("攻击力:", dic[id].atk);
dic[id].speed = EditorGUILayout.IntField("速度:", dic[id].speed);
GUILayout.BeginHorizontal();
skillid = EditorGUILayout.Popup(skillid, skillArr.ToArray());
if(GUILayout.Button("添加技能"))
{
dic[id].skillid.Add(skillid);
}
GUILayout.EndHorizontal();
if (dic[id].skillid.Count > 0)
{
foreach (var item in dic[id].skillid)
{
GUILayout.BeginHorizontal();
SkillData skillData = ConfigManager.Instance.GetData<SkillData>(ConfigManager.skillPath, item);
if(GUILayout.Button(skillData.name))
{
SkillEditor.id = item;
SkillEditor.Init();
}
if(GUILayout.Button("删除技能"))
{
dic[id].skillid.RemoveAt(item);
break;
}
GUILayout.EndHorizontal();
}
}
if(GUILayout.Button("保存"))
{
ConfigManager.Instance.Save(ConfigManager.rolePath, dic);
AssetDatabase.Refresh();
}
}
}
(5)技能编辑器
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class SkillEditor : EditorWindow
{
static Dictionary<int, SkillData> dic;
static List<string> nameArr;
static List<string> buffArr;
[MenuItem("Editor/SkillEditor")]
public static void Init()
{
GetWindow<SkillEditor>("SkillEditor").Show();
dic = ConfigManager.Instance.GetDic<SkillData>(ConfigManager.skillPath);
nameArr = ConfigManager.Instance.GetNames<SkillData>(ConfigManager.skillPath, "创建新技能");
buffArr = ConfigManager.Instance.GetNames<BuffData>(ConfigManager.buffPath);
}
public static int id;
Sprite sprite;
private void OnGUI()
{
id = EditorGUILayout.Popup("选择", id, nameArr.ToArray());
if(!dic.ContainsKey(id))
{
dic.Add(id, new SkillData());
dic[id].id = id;
}
dic[id].name = EditorGUILayout.TextField("技能名称:", dic[id].name);
if (dic[id].iconPath.Length > 0)
{
sprite = Resources.Load<Sprite>(dic[id].iconPath);
}
sprite = (Sprite)EditorGUILayout.ObjectField(sprite, typeof(Sprite), false, GUILayout.Width(100), GUILayout.Height(100));
if (sprite != null)
{
string path = AssetDatabase.GetAssetPath(sprite);
path = path.Replace("Assets/Resources/", "");
path = path.Replace(".jpg", "");
path = path.Replace(".png", "");
dic[id].iconPath = path;
}
dic[id].dis = EditorGUILayout.FloatField("施法距离:", dic[id].dis);
dic[id].range = EditorGUILayout.FloatField("施法范围:", dic[id].range);
if(GUILayout.Button("保存技能"))
{
ConfigManager.Instance.Save(ConfigManager.skillPath, dic);
AssetDatabase.Refresh();
}
}
}
注意:在Assets/Resources旗下一定要创建一个叫Json的文件夹,因为我们保存(Save)的json是在这个文件夹旗下
三.效果
(1)角色编辑器
(2)技能编辑器