版本管理
需要版本管理的文件夹只有Assets、ProjectSettings和UnityPackageManager。
unity界面
切换pivot和center选项,可以在选中的一组对象(或有父子关系的对象)间切换轴点是自身还是中心。global和local可以切换对象的坐标系,方便移动。
修改game视图的分辨率,可以查看ui在不同分辨率中的表现。
编辑器扩展
Project窗口右键菜单
using UnityEngine;
using UnityEditor;
public class AssetsEditor {
// 顶部工具栏Assets和Project窗口中右键资源时会显示此菜单
[MenuItem("Assets/My Tools/Tools 1", false, 1)]
static void MyTools(){
Debug.Log(Selection.activeObject.name);
}
}
Create创建菜单
using UnityEngine;
using UnityEditor;
public class AssetsEditor {
// Create创建菜单,通过菜单路径(“Assets/Create”)识别
[MenuItem("Assets/Create/My Create/Cube", false, 2)]
static void CreateCube(){
GameObject.CreatePrimitive(PrimitiveType.Cube);
}
}
Project窗口中选中资源,右侧显示按钮等UI元素
using UnityEngine;
using UnityEditor;
public class AssetsEditor {
// Project窗口中选中资源,右侧会出现按钮
// [InitializeOnLoadMethod] 表示此方法会在C#代码每次编译完成后调用
[InitializeOnLoadMethod]
static void InitializeOnLoadMethod(){
// 监听此方法可以绘制GUI
EditorApplication.projectWindowItemOnGUI = delegate(string guid, Rect selectionRect){
// 在Project窗口中选中一个资源
if(Selection.activeObject &&
guid == AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(Selection.activeObject))){
// 设置拓展按钮区域
float width = 50f;
selectionRect.x += (selectionRect.width - width);
selectionRect.y += 2f;
selectionRect.width = width;
GUI.color = Color.red;
if(GUI.Button(selectionRect, "click")){
Debug.LogFormat("click: {0}", Selection.activeObject.name);
};
GUI.color = Color.white;
}
};
}
}
Project 窗口中的事件监听
可以监听资源创建、删除、移动和保存方法
using UnityEngine;
using UnityEditor;
// 继承 AssetModificationProcessor 可以监听资源创建、删除、移动和保存方法
public class MyAssetModification : UnityEditor.AssetModificationProcessor {
[InitializeOnLoadMethod]
static void InitializeOnLoadMethod(){
// 全局监听Project 窗口资源是否发生改变(添加,删除,移动)
EditorApplication.projectChanged += delegate(){
Debug.Log("project window change");
};
}
// 监听“双击鼠标左键,打开资源”事件
public static bool IsOpenForEdit(string assetPath, out string message){
message = null;
Debug.LogFormat("IsOpenForEdit path: {0}", assetPath);
// return true 表示资源可以打开,false表示不可以在unity中打开
return true;
}
// 监听资源即将被创建
public static void OnWillCreateAsset(string path){
Debug.LogFormat("OnWillCreateAsset path: {0}", path);
}
// 监听资源将被删除
public static AssetDeleteResult OnWillDeleteAsset(string assetPath, RemoveAssetOptions option){
Debug.LogFormat("OnWillDeleteAsset delete: {0}", assetPath);
// AssetDeleteResult.DidNotDelete 表示资源可以删除
return AssetDeleteResult.DidNotDelete;
}
}
Hierarchy 窗口扩展
添加Create菜单,添加对象右侧按钮
using UnityEditor;
using UnityEngine;
public class MyHierarchyEditor {
// HierarchyEditor Creat按钮下的菜单都在GameObject路径下面
[MenuItem("GameObject/My Create/Cube", false, 0)]
static void CreateCube(){
GameObject.CreatePrimitive(PrimitiveType.Cube);
}
// 选中 Hierarchy 中对象右侧显示按钮
[InitializeOnLoadMethod]
static void InitializeOnLoadMethod(){
// 监听渲染回调
EditorApplication.hierarchyWindowItemOnGUI = delegate(int instanceID, Rect selectionRect){
if(Selection.activeObject &&
instanceID == Selection.activeObject.GetInstanceID()){
// 设置拓展按钮区域
float width = 50f;
float height = 20f;
selectionRect.x += (selectionRect.width - width);
selectionRect.width = width;
selectionRect.height = height;
if(GUI.Button(selectionRect, "click")){
Debug.LogFormat("click: {0}", Selection.activeObject.name);
};
}
};
}
}
禁用对象(HideFlags)
设置对象的HideFlags 可以控制对象在编辑器中的销毁、保存和可见性。入下图对象处于不可编辑状态
using UnityEditor;
using UnityEngine;
public class MyHierarchyEditor {
// 设置游戏对象锁定(hideFlags)
[MenuItem("GameObject/3D Object/Lock/Lock", false, 0)]
static void Lock(){
if(Selection.gameObjects != null){
foreach(var gameobject in Selection.gameObjects){
gameobject.hideFlags = HideFlags.NotEditable;
}
}
}
[MenuItem("GameObject/3D Object/Lock/UnLock", false, 0)]
static void UnLock(){
if(Selection.gameObjects != null){
foreach(var gameobject in Selection.gameObjects){
gameobject.hideFlags = HideFlags.None;
}
}
}
}
Inspector 窗口扩展
给Camera Inspector窗口添加按钮,扩展自定义组件时同理
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Camera))]
public class MyCameraEditor : Editor {
// 重写 OnInspectorGUI 方法绘制
public override void OnInspectorGUI(){
if(GUILayout.Button("button")){
Debug.Log("click");
}
base.OnInspectorGUI();
}
}
组件添加Context 菜单,并且获取组件中的属性
using UnityEditor;
using UnityEngine;
public class MyHierarchyEditor {
// 修改组件的Context 菜单
// 路径中的 Transform 表示给Transform 组件添加菜单,Component 表示给所有组件添加
[MenuItem("CONTEXT/Transform/New Context")]
static void NewContext(MenuCommand command){
Transform trans = command.context as Transform;
Debug.Log("NewContext :" + trans.position);
}
}
Scene 窗口扩展
依靠Gizmos 对象可以在Scene 窗口中绘制各种对象
给Camera 添加辅助图形,将绘制脚本添加到Camera对象上。由于不是Editor脚本,所以不可放在Editor文件夹下。
using UnityEngine;
public class CameraSceneExtend : MonoBehaviour{
// 选中一个对象时绘制
void OnDrawGizmosSelected(){
Gizmos.color = Color.red;
Gizmos.DrawLine(transform.position, Vector3.one);
Gizmos.DrawCube(Vector3.one, Vector3.one);
}
// 无需选中对象即可绘制
void OnDrawGizmos(){
Gizmos.DrawSphere(transform.position, 1);
}
}
Scene 窗口绘制UI
需继承 Editor 类在Scene 中绘制UI,需要注意的是重写Inspector 窗口和Scene 窗口都需要[CustomEditor(typeof(Camera))],这里需要写在一个编辑器脚本中,否则只会有一个生效
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Camera))]
public class MyCameraEditor : Editor {
// 重写 OnInspectorGUI 方法绘制
public override void OnInspectorGUI(){
if(GUILayout.Button("button")){
Debug.Log("click");
}
base.OnInspectorGUI();
}
// 绘制Scene 窗口
void OnSceneGUI(){
Camera camera = target as Camera;
if(camera != null){
Handles.color = Color.red;
Handles.Label(camera.transform.position, camera.transform.position.ToString());
// EditorGUI方法要放在Handles.BeginGUI 中
Handles.BeginGUI();
GUI.backgroundColor = Color.green;
if(GUILayout.Button("click", GUILayout.Width(200f))){
Debug.LogFormat("click = {0}", camera.name);
}
GUILayout.Label("Label.");
Handles.EndGUI();
}
}
}
Scene 窗口中绘制常驻辅助UI和右键菜单
上面都是选中一个对象后在Scene 窗口中绘制,下面是常驻Scene 的绘制方式
using UnityEditor;
using UnityEngine;
public class MySceneUIEditor {
[InitializeOnLoadMethod]
static void InitializeOnLoadMethod(){
// 全局监听SceneView.onSceneGUIDelegate
SceneView.onSceneGUIDelegate = delegate(SceneView sceneView){
Handles.BeginGUI();
GUI.Label(new Rect(0f, 0f, 50f, 15f), "标题");
Handles.EndGUI();
// 绘制右键菜单
// 鼠标右键抬起
Event e = Event.current;
if(e != null && e.button == 1 && e.type == EventType.MouseUp){
Vector2 mousePosition = e.mousePosition;
var options = new GUIContent[]{
new GUIContent("Test1"),
new GUIContent(""),
new GUIContent("Test/Test2"),
new GUIContent("Test/Test3"),
};
var selected = -1;
var userData = Selection.activeGameObject;
var width = 100;
var height = 100;
var position = new Rect(mousePosition.x,mousePosition.y - height, width, height);
EditorUtility.DisplayCustomMenu(position, options, selected,
delegate(object data, string[] opt, int select){
Debug.Log(opt[select]);
}, userData);
e.Use();
}
};
}
}
Game 窗口扩展
需要在脚本类名上方使用[ExecuteInEditMode] ,这类脚本一般仅在编辑器中使用。
using UnityEngine;
#if UNITY_EDITOR
[ExecuteInEditMode]
public class MyCameraGameEditorUI : MonoBehaviour {
void OnGUI () {
if(GUILayout.Button("click")){
Debug.Log("click");
}
}
}
#endif
EditorWindow 绘制自定义窗口
绘制窗口和窗口右上角的下拉菜单
using UnityEditor;
using UnityEngine;
// IHasCustomMenu 可以自定义窗口右上角的下拉菜单
public class MyEditorWindow : EditorWindow, IHasCustomMenu {
// 打开窗口
[MenuItem("Window/My Window")]
static void Init(){
MyEditorWindow window = (MyEditorWindow)EditorWindow.GetWindow(typeof(MyEditorWindow));
window.Show();
}
void IHasCustomMenu.AddItemsToMenu(GenericMenu menu){
menu.AddDisabledItem(new GUIContent("Disable"));
menu.AddItem(new GUIContent("Test1"), true, () => {
Debug.Log("Test1");
});
menu.AddSeparator("Test/");
menu.AddItem(new GUIContent("Test/Test2"), true, () => {
Debug.Log("Test2");
});
}
}
绘制预览窗口,Inspector 窗口下方
默认cube是没有预览信息的
using UnityEditor;
using UnityEngine;
[CustomPreview(typeof(GameObject))]
public class MyObjectPreview : ObjectPreview {
public override bool HasPreviewGUI(){
return true;
}
public override void OnPreviewGUI(Rect r, GUIStyle background){
GUILayout.Label("label");
}
}