需要存储,就需要需要序列化,需要序列化成一个字符串
需要使用的化得经过反序列化才能使用
编辑器就是给类加标签,json与之差不多
一个变量可以加多个特性
[Hideinspector]隐藏
[Serializablefild]显示
[range(1,5)]范围
[tooltop("xxx")] 提示,添加变量悬浮提示文字
[Header("xxx")] 加在前面的文字
[Space(50)] 与上一行留像素距离
[Muiltline(5)] 加行,多行
[Textarea(5,10)] 默认五行,再多十行,再多就滚动条
枚举是下拉菜单 多选直接上2的n次幂
[Contexmenu("xxx")] 给小齿轮加回调函数
void 方法名(){}
[Contexmenuitem("xx","xx")],提示+函数名字
void xx(){}
[Requirecomponent(typeof())] 绑定类
[Executeineditmode] 在编辑的时候执行一下
[Addcomponentmenu(xxx,排第几)] 添加到addcomponent里
异或位运算。
相同为零,不同为一。
A与B异或得到C,那么。B与C异或,可再次获得A。A与C异或,可再次获得B.
所以如果A是明文,B是密钥,C就是密文,使用异或实现的算法,可以将C密文利用B密钥,解出A即原始文字。
监视器脚本,外挂式编程
Editor目录下建立外挂式开发脚本,将编辑器脚本与外挂脚本关联
外挂脚本在Editor下,所以不会被打入游戏包 不继承mono,而是继承editor 引入编辑器的命名空间,检视器属于编辑器开发范畴,继承Editor类,使用编辑器相关的成员变量和生命周期函数
找关系,引入特性[Customeditor(typeof(类名))],将编辑器开发脚本,与需要编辑的组件建立外挂联系
玩家类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum PlayerProfression
{
Warrior=0,
Wizard=1
}
public enum PlayerLoveColor
{
Green=1,
Red=2,
Pink=4,
}
//将player组件添加到addcompent上
//第一个参数:分类名/组件名
//第二个参数:列表中显示的顺序
[AddComponentMenu("自定义控制器/玩家控制器",1)]
//使生命周期函数,在编辑状态下可以执行,在游戏中也可以正常使用
//update()在场景中对象发生变化或项目组织发生变化时会在编辑器下执行
[ExecuteInEditMode]
//关于类型和类名
//BoxCollider是类名,适用于函数提供泛型方法
//typeof(BoxCollider):System.Type,c#的类型,适用于需要system.Type参数
//当前组件依赖于盒子碰撞器
//当前组件挂在对象上时,盒子碰撞体会一起被添加上去
//player没有被移除时,盒子碰撞体也不能被移除
[RequireComponent(typeof(BoxCollider))]
public class Player : MonoBehaviour
{
public int ID;
public string Name;
public float Atk;
public bool isMan;
public Vector3 HeadDir;
public Color Hair;
public GameObject Weapon;
public Texture Cloth;
public PlayerProfression Pro;
public PlayerLoveColor LoveColor;
public List<string> Items;
private void Update()
{
// Debug.Log("Update");
}
}
外挂的玩家类编辑器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//步骤1:引入编辑器的命名空间,检视器属于编辑器开发范畴
using UnityEditor;
//步骤3:将编辑器开发脚本于需要编辑的组件脚本简历外挂关联关系
//外挂脚本因为储存在Editor目录下,所以不会被最终打入游戏包
//不继承Mono,而是继承Editor
[CustomEditor(typeof(Player))]
//步骤2:继承Editor类,使用编辑器相关的成员变量和生命周期函数
public class PlayerEditor : Editor
{
public Player _Component;
//步骤4:需要在当前的外挂脚本中,获得需要被扩展得Player组件对象
//当关联组件所在对象被选中或组件被添加时,调用
private void OnEnable()
{
//步骤5:获取Player组件对象
_Component = target as Player;
}
//当关联组件所在对象被销毁或组件被移除时,调用
private void OnDisable()
{
_Component = null;
}
//用于绘制检视面板的生命周期函数
public override void OnInspectorGUI()
{
//标题显示
EditorGUILayout.LabelField("人物相关属性");
//整数
_Component.ID = EditorGUILayout.IntField("玩家ID", _Component.ID);
//文本
_Component.Name = EditorGUILayout.TextField("玩家名称", _Component.Name);
//浮点数
_Component.Atk = EditorGUILayout.FloatField("玩家攻击力", _Component.Atk);
//布尔
_Component.isMan = EditorGUILayout.Toggle("是否为男性", _Component.isMan);
//向量
_Component.HeadDir = EditorGUILayout.Vector3Field("头部方向", _Component.HeadDir);
//颜色
_Component.Hair = EditorGUILayout.ColorField("头发颜色", _Component.Hair);
//对象数据类型的绘制
//参数1:标题 参数2:原始组件的值
//参数3:成员变量的类型 参数4:是否可以将场景中的对象拖给这个变量
_Component.Weapon = EditorGUILayout.ObjectField("持有武器", _Component.Weapon,
typeof(GameObject), true)as GameObject;
_Component.Cloth = EditorGUILayout.ObjectField("衣服材质贴图", _Component.Cloth,
typeof(Texture), false) as Texture;
//枚举数据类型的绘制
//整数转枚举
//单选枚举(标题,组件上的原始值)
_Component.Pro = (PlayerProfression)EditorGUILayout.EnumPopup("玩家职业", _Component.Pro);
_Component.LoveColor = (PlayerLoveColor)EditorGUILayout.EnumFlagsField("玩家喜欢的颜色", _Component.LoveColor);
//终极数据类型的绘制
//更新可序列化数据
serializedObject.Update();
//通过成员变量名找到组件上的成员变量
SerializedProperty sp = serializedObject.FindProperty("Items");
//可序列化数据绘制(取到数据,标题,是否将所有获得序列化的数据显示出来)
EditorGUILayout.PropertyField(sp, new GUIContent("道具信息"), true);
//将修改的数据写入到可序列化的原始数据中
serializedObject.ApplyModifiedProperties();
//滑动条的绘制
//滑动条显示(1.标题2.原始变量3.最小值,4.最大值)
_Component.Atk = EditorGUILayout.Slider(new GUIContent("玩家攻击力"), _Component.Atk, 0, 100);
if (_Component.Atk > 80)
{
//显示消息红框
EditorGUILayout.HelpBox("攻击力太高了", MessageType.Error);
}
if (_Component.Atk < 20)
{
//显示消息黄框
EditorGUILayout.HelpBox("攻击力太低了", MessageType.Warning);
}
//按钮显示和元素排列
//(按钮是否被按下)显示按钮(按钮名称)
GUILayout.Button("来个按钮");
GUILayout.Button("来个按钮");
//开始横向排列绘制
EditorGUILayout.BeginHorizontal();
GUILayout.Button("再来个按钮");
GUILayout.Button("再来个按钮");
//结束横向排列绘制
EditorGUILayout.EndHorizontal();
if(GUILayout.Button("测试点击"))
{
Debug.Log("测试点击");
}
}
}
菜单栏上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class Menu : Editor
{
[MenuItem("工具/导出AB资源包")]
private static void BuildAb()
{
//Debug.Log("导出AB包");
Debug.Log(Application.persistentDataPath);
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class PopupWindow : EditorWindow
{
[MenuItem("工具/创建窗口")]
static void OpenWindow()
{
PopupWindow window= GetWindow<PopupWindow>(false, "弹窗", true);
window.minSize=new Vector2(400,300);
window.maxSize=new Vector2 (800,600);
}
//开窗口调用
private void OnEnable()
{
Debug.Log("onenble");
}
//关窗口调用
private void OnDisable()
{
Debug.Log("ondisenble");
}
//窗口开启调用
private void Update()
{
Debug.Log("update");
}
private void OnGUI()
{
if(GUILayout.Button("测试点击"))
{
Debug.Log("测试点击");
}
}
//场景结构发生变化执行回调函数
private void OnHierarchyChange()
{
Debug.Log("hierarchy");
}
//项目结构发生变化执行回调函数
private void OnProjectChange()
{
Debug.Log("Project");
}
//选中物体发生变化执行回调函数
private void OnSelectionChange()
{
//获取当前选中的物体的名称
Debug.Log(Selection.activeGameObject.name);
}
}
编辑器工具制作
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]//在编辑模式下可以执行一些生命周期函数
public class NodeManage : MonoBehaviour
{
//储存了所有编辑器下的节点,并使用预制体显示
public List<GameObject> nodes;
private void Start()
{
nodes=new List<GameObject>();
}
private void Update()
{
for (int i = 0; i < nodes.Count-1; i++)
{
Debug.DrawLine(nodes[i].transform.position,
nodes[i+1].transform.position,
Color.red,Time.deltaTime);
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class NodeWindow : EditorWindow
{
private static NodeWindow window;
private static GameObject nodeManager;
public static void OpenWindow(GameObject manager)
{
nodeManager = manager;
//真正开启一个窗口
window = GetWindow<NodeWindow>();
}
private void Update()
{
//通过窗口的update每帧执行一次,当前被选中的对象为板子
Selection.activeGameObject = nodeManager;
}
public static void CloseWindow()
{
window.Close();
}
}
[CustomEditor(typeof(NodeManage))]
public class NodeManageEditor : Editor
{
private NodeManage _nodeManage;
private bool isEditor;
//当选中带有nodemanage组建的时候 获得组件
private void OnEnable()
{
_nodeManage = (NodeManage) target;
}
//绘制组件的生命周期函数
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(_nodeManage.gameObject);
isEditor = true;
}
//结束编辑的开关
else if (isEditor&&GUILayout.Button("结束编辑"))
{
NodeWindow.CloseWindow();
isEditor = false;
}
if (GUILayout.Button("删除最后一个节点"))
{
RemoveAtLast();
}
else if (GUILayout.Button("删除所有节点"))
{
RemoveAll();
}
}
private RaycastHit _hit;
//当选中关联的脚本挂载的物体
//当鼠标再scene视图下发生变化时,执行该方法,比如鼠标的移动,鼠标的点击
//有点类似update函数,发送射线
private void OnSceneGUI()
{
//非编辑状态下不能生成路点
if (!isEditor)
{
return;
}
//当鼠标按下左键时发射一个射线
//非运行的时候,使用event类
//Event.current.button 判断鼠标是哪个按键的
//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))
{
Debug.Log("213");
//需要检测到的点实例化,路点
InstancePathbNode(_hit.point + Vector3.up*0.1f);
}
}
}
//生成节点
void InstancePathbNode(Vector3 position)
{
//点预制体
GameObject prefab = Resources.Load<GameObject>("PathNode");
//点对象生成到plane的子物体下
GameObject pathNode = Instantiate(prefab, position, prefab.transform.rotation,
_nodeManage.transform);
//把生成的点放在路径里
_nodeManage.nodes.Add(pathNode);
}
private void RemoveAtLast()
{
if (_nodeManage.nodes.Count>0)
{
//场景中删除游戏物体
DestroyImmediate(_nodeManage.nodes[_nodeManage.nodes.Count-1]);
//并把该节点从列表中删除
_nodeManage.nodes.RemoveAt(_nodeManage.nodes.Count - 1);
}
}
private void RemoveAll()
{
//场景中删除游戏物体
foreach (var item in _nodeManage.nodes)
{
DestroyImmediate(item);
}
//并把该节点从列表中删除
_nodeManage.nodes.Clear();
}
}