求助,Unity编辑器反应方程式编辑器很慢

2985人阅读
Unity3D(3)
最近在写Editor插件,遇到一个很迷知的现象,在写编辑器的时候,发现一个Item位置不对,需要在代码里面调整下,Unity编译结束后,会发现有些变量被Unity销毁了,有些变量值仍然被保留。这个问题需要关心的目的是,如果写的是一个比较大型的插件,给别人用的时候,发现一些项目资源忘记更新了,就顺手切到目录下更新,有时候会更新到一些程序脚本,再切换回Unity的时候,Unity会自动编译,这样之前做的操作可能就被自动清空掉了,所以了解EditorWindow里面什么类型的变量会在Unity编译时候被销毁,什么类型的不会被销毁,是非常有必要的。
我测试了一下,得到的一些心得。
在EditorWindow类中的基础数据类型(int,float,string,double..),unity里面序列化的对象(Vector3,Quaternion,GameObject,Transform,继承Component,继承ScriptableObject),只要窗口不被关闭,这些变量数据不会因为程序重新编译被销毁。
但是如果这些类型的变量为静态类型,每次编译后,这个静态变量就会被销毁掉。
还有就是需要编译后不被销毁的对象不能这样写:
public int ID{}
以下是测试的代码:
using UnityE
using UnityE
using System.C
public class TestEditor:EditorWindow {
[MenuItem(&Tools/Test Window&)]
private static void Open()
EditorWindow.CreateInstance&TestEditor&().Show();
//-------------------------------------------------------//
private string testS
//不会销毁
private static string testStaticS
//会被销毁
private GameObject testGameO
//不会销毁
public static GameObject testStaticGameO
//会被销毁
public static string testPublicStaticS
//会被销毁
private TestDataNoSerialize testNoSerializeData =new TestDataNoSerialize();
//会被销毁
private TestDataSerialize testSerializeData = new TestDataSerialize();
//不会销毁
private TestScriptableObject testScriptO
//不会销毁
//------------------------------------------------------//
private void OnGUI()
testString =EditorGUILayout.TextField(&Test String&, testString);
testStaticString = EditorGUILayout.TextField(&Test Static String&, testStaticString);
testPublicStaticString = EditorGUILayout.TextField(&Test Public Static String&, testPublicStaticString);
testGameObject = EditorGUILayout.ObjectField(&Test Game Object&,testGameObject,typeof(GameObject),true) as GameO
testStaticGameObject = EditorGUILayout.ObjectField(&Test Static Game Object&, testStaticGameObject, typeof(GameObject), true) as GameO
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.LabelField(&No Serialize Data&);
testNoSerializeData.Name =EditorGUILayout.TextField(&Name&, testNoSerializeData.Name);
testNoSerializeData.ID = EditorGUILayout.IntField(&ID&, testNoSerializeData.ID);
testNoSerializeData.Obj = EditorGUILayout.ObjectField(&Game Object&, testNoSerializeData.Obj, typeof(GameObject), true) as GameO
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.LabelField(&Serialize Data&);
testSerializeData.Name = EditorGUILayout.TextField(&Name&, testSerializeData.Name);
testSerializeData.ID = EditorGUILayout.IntField(&ID&, testSerializeData.ID);
testSerializeData.Obj = EditorGUILayout.ObjectField(&Game Object&, testSerializeData.Obj, typeof(GameObject), true) as GameO
if (testScriptObject == null)
testScriptObject =ScriptableObject.CreateInstance&TestScriptableObject&();
Debug.Log(&Create Instance&);
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.LabelField(&ScriptableObject Data&);
testScriptObject.Name = EditorGUILayout.TextField(&Name&, testScriptObject.Name);
testScriptObject.ID = EditorGUILayout.IntField(&ID&, testScriptObject.ID);
testScriptObject.Obj = EditorGUILayout.ObjectField(&Game Object&, testScriptObject.Obj, typeof(GameObject), true) as GameO
public class TestDataNoSerialize {
public string N
public int ID;
public GameObject O
[System.Serializable]
public class TestDataSerialize
public string N
public int ID
//会被销毁
public GameObject O
public class TestScriptableObject:ScriptableObject{
public string N
public int ID;
public GameObject O
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:20489次
排名:千里之外
评论:16条
(2)(1)(1)(1)(1)(1)Unity EditorWindow中响应按键事件地狱为王unity学习笔记(26)
原文地址:
这篇文章主要分享unity中与editor插件等相关的使用,比较基础,不过如果都掌握了就可以扩展写一些unity插件了,平时开发中也会提升工作效率。
editor相关脚本一定要放在Editor文件夹下,继承monobehaviour的文件不要放到Editor文件夹下。
monobehaviour相关的编辑器功能
首先常用的在继承monobehaviour类中写public变量可以在inspector中序列化可编辑一般人都知道了,下面是一些可以更有效率更酷的方法。
增强序列化属性
public bool isGood = false;
[Tooltip(&hp&)]
public int life = 0;
[Range(0f, 1f)]
public float CloudRange = 0.5f;
[Range(0, 15)]
public int CloudRangeInt = 1;
[Header(&OtherAttr&)]
public float CloudHeader = 1f;
[Space(30)]
public float CloudSpace = 1f;
[HideInInspector]
public float CloudHideInInspector = 1f;
[NonSerialized]
public float CloudNonSerialized = 1f;
[SerializeField]
private bool CloudSerializeField = true;1234567891011121314151617181920212223242512345678910111213141516171819202122232425
效果如下图,对于一些有范围的数值可以用range做个slider让策划来调节,可以用header和space来组织面板的外观,也可以针对不同的属性进行是否序列化的选择。
也可以序列化一个类
[Serializable]
public class SerializableClass {
public int x = 0;
public Vector2
public SerializableClass serializedO1234567812345678
组件面板的上下文菜单
有时在monobehaviour中写一些方法可以初始化一些值或者随机产生某个值这种需求,都可以在菜单中触发,只要简单的加一行即可。
[ContextMenu(&Init&)]
void Init()
isGood = false;
[ContextMenu(&Random value&)]
void RandomValue()
Debug.Log(&TestContextMenu & + gameObject.name);
isGood = true;
life = UnityEngine.Random.Range(1, 100);
}12345678910111213141234567891011121314
效果如下图,点击init就会赋一个初始的值,点击randomvalue可以随机产生一个life的值,这就是最简单的editor工具了
inspector相关的编辑器功能
如果要在inspector中加上一些更高级的功能就需要使用editor相关的方法了
这是要使用的TestInspector类代码
[CustomEditor(typeof(TestInspector))]
public class CloudTools : Editor {
#region inspector
GameObject rootO
SerializedObject seriO
SerializedProperty headC
private static bool toggle = true;
public void OnEnable()
seriObject = base.serializedO
headColor = seriObject.FindProperty(&headColor&);
var tscript = (TestInspector)(base.serializedObject.targetObject);
if (tscript != null)
rootObject = script.gameO
Console.Error.WriteLine(&tscript is null&);
public void OnDisable()
var tscript = (TestInspector)(base.serializedObject.targetObject);
if (tscript == null)
Debug.Log(&tscript == null&);
Debug.Log(&tscript != null&);
seriObject = null;
script = null;
rootObject = null;
public override void OnInspectorGUI()
base.OnInspectorGUI();
seriObject.Update();
script = target as TestI
if (GUILayout.Button(&RandomNum&))
Undo.RecordObject(script, &revert random num&);
script.RandomNum(script.num);
GUILayout.BeginHorizontal();
if (GUILayout.Button(&SaveScene&))
EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();
if(GUILayout.Button(toggle ? &untoggle& : &toggle&))
toggle = !
GUILayout.EndHorizontal();
script.isAlive = EditorGUILayout.BeginToggleGroup(&isAlive&, script.isAlive);
if (script.isAlive)
script.life = EditorGUILayout.Slider(&life&, script.life, 0, 100f);
EditorGUILayout.EndToggleGroup();
EditorGUILayout.PropertyField(headColor);
seriObject.ApplyModifiedProperties();
EditorGUILayout.LabelField(&life & + script.life, GUILayout.Width(200));
Repaint();
#endregion
}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
其中需要用OnEnable和OnDisable来做初始化和清理工作,OnInspectorGUI方法可以类比monobehaviour中的OnGUI,做ui渲染和ui事件处理。
里面还注册了UnDo,好处是可以通过ctrl+z来进行撤销操作,这样才更完美更像一个完善的unity插件。
代码也没什么难度,我也做了下简单的注释,执行一下看看效果大部分人就都理解了。效果如下图
各种上下文菜单
之前可以在monobehaviour中加入[ContextMenu(&Random value&)]来生成对应脚本组件面板的上下文菜单,那么如果要生成一个在transform组件上的菜单怎么办
[MenuItem(&CONTEXT/Transform/RandomPosition&)]
static void ContextMenu_TransformRandomPosition()//随机改变transform组件的position
Debug.Log(&ContextMenu_Transform&)
Transform[] transforms = Selection.GetTransforms(SelectionMode.TopLevel | SelectionMode.OnlyUserModifiable)
foreach (Transform transform in transforms)
transform.localPosition = new Vector3(UnityEngine.Random.Range(-10, 10),
UnityEngine.Random.Range(-10, 10),
UnityEngine.Random.Range(-10, 10))
Debug.Log(transform.localPosition)
}1234567891011121312345678910111213
效果如下图,如果策划或者美术需要对transform的position干这种随机的事,是不是就可以这么搞了?或者对collider、rigibody之类的组件加上一些属性模板的设置,会很方便吧
带勾选的菜单
在editor中加个菜单item是件很容易的事情,那么如果这个菜单是可以勾选的呢?是不是可以解决一些开关的问题?
const string Menu_Checked = &Cloud/MenuChecked&;
const string Key_MenuChecked = &MenuChecked&;
[MenuItem(Menu_Checked)]
static void MenuChecked()
bool flag = Menu.GetChecked(Menu_Checked);
Debug.Log(&Key_MenuChecked to 0&);
PlayerPrefs.SetInt(Key_MenuChecked, 0);
Debug.Log(&Key_MenuChecked to 1&);
PlayerPrefs.SetInt(Key_MenuChecked, 1);
Menu.SetChecked(Menu_Checked, !flag);
[MenuItem(Menu_Checked, true)]
public static bool IsMenuChecked()
Menu.SetChecked(Menu_Checked, PlayerPrefs.GetInt(Key_MenuChecked, 0) == 1);
return true;
}12345678910111213141516171819202122232425261234567891011121314151617181920212223242526
效果如下图,其中需要一个菜单的valid函数来判断菜单是否在勾选状态,这里用了playprefs,在windows上就写到注册表里了
project面板中的菜单
这个菜单是加到了Assets下面,那么在project面板中右键也可以看到,这种菜单可以干什么呢,我也没想好,不过干些修改assetsimport属性或者修改一些资源等等还是挺好用的吧
[MenuItem(&Assets/TestAssets&)]
static void MenuAssets()
if(Selection.activeObject == null)
Debug.Log(&TestAssets choose null&);
Debug.Log(&TestAssets name = & + Selection.activeObject.name);
}1234567891011121312345678910111213
一般这种菜单都可以通过Selection.activeObject/activeGameObject等等来获取选中对象,当然也可以获取多选的多个对象,这个看下api就知道了
hierarchy面板菜单
这个菜单还是比较实用的,相对来说也不太一样
[MenuItem(&GameObject/Create Other/TestGameObject&)]
static void MenuGameObject()
Debug.Log(&TestGameObject&);
}1234512345
将菜单加到GameObject下面,就可以在hierarchy里右键看到了
那么基于这个菜单我们可以做个比较实用的功能,例如右键hierarchy中场景的一个GameObject并且对它进行SetActive为true or false的操作,代码如下:
//快捷键可以为%=ctrl/cmd #=shift &=alt LEFT/RIGHT/UP/DOWN F1-F12,HOME END PGUP PGDN _a~_z
[MenuItem(&GameObject/SetActive _a&, false, 11)] //11及以后可以在Camera之后显示
static void MenuGameObjectSetActive()//通过按a键来设置所选择GameObject的active状态
Debug.Log(&MenuGameObjectSetActive&)
if(Selection.activeGameObject != null)
Undo.RecordObject(Selection.activeGameObject, &SetActive& + Selection.activeGameObject.activeSelf + & & + Selection.activeGameObject.name)
Selection.activeGameObject.SetActive(!Selection.activeGameObject.activeSelf)
Debug.Log(Selection.activeObject.name)
[MenuItem(&GameObject/SetActive&, true, 11)]
static bool CheckIsGameObject()//判断是否显示该菜单的校验方法,如果没选择GameObject为灰
UnityEngine.Object selectedObject = Selection.activeObject
if(selectedObject != null && selectedObject.GetType() == typeof(GameObject))
Debug.Log(selectedObject.name)
return true
return false
}123456789101112131415161718192021222324123456789101112131415161718192021222324
其中做校验的方法是为了在不选中GameObject的时候能够将菜单灰掉。另外这种菜单可以绑定一个快捷键,这个例子是绑定了a键,菜单中也可以看出来。
最终效果就成了:我选中一个GameObject,只要按下a键就可以SetActive(false),再按下变成true,还是比较实用的吧,基于此可以做很多实用的东西。效果如下图
对话框比较简单,就是一些内置的api,具体可以查看api,支持了例如简单和复杂对话框、打开保存文件对话框、进度条等等功能
EditorUtility.DisplayCancelableProgressBar(&ok&, &done&, 0.7f)&
EditorUtility.ClearProgressBar();&
EditorUtility.OpenFilePanel(&open&, &d:/&, &.txt&);
如果要做的事情可能不是与某个GameObject相关,inspector不能满足要求,那么可以创建一个新的窗口,创建新的editor窗口需要继承EditorWindow,代码如下
[CustomEditor(typeof(CloudWindow))]
public class CloudWindow : EditorWindow {
#region 对话框
[MenuItem(&Cloud/ShowEditorTestPanel&)]
public static void ConfigDialog()
EditorWindow.GetWindow(typeof(CloudWindow));
public UnityEngine.Object go = null;
string goName= &default&;
float life = 100f;
bool isAlive = true;
bool toggleE
void OnGUI()
GUILayout.Label(&Label Test&, EditorStyles.boldLabel);
go = EditorGUILayout.ObjectField(go, typeof(UnityEngine.Object), true);
if (GUILayout.Button(&Button Test&))
if (go == null)
Debug.Log(&go == null&);
Debug.Log(go.name);
goName = EditorGUILayout.TextField(&textfield&, goName);
toggleEnabled = EditorGUILayout.BeginToggleGroup(&optional settings&, toggleEnabled);
if (toggleEnabled)
isAlive = EditorGUILayout.Toggle(&isalive&, isAlive);
life = EditorGUILayout.Slider(&life&, life, 0, 100);
EditorGUILayout.EndToggleGroup();
#endregion
}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484912345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
好像代码也不复杂,也没什么难度就是常见的ui绘制,效果如下:
如果有更高的需求可能需要更深入的研究一下unity中editor的相关api和文档
unity还提供了可以在scene窗口中做一些操作,例如画一些辅助线、显示label、操作handler等,具体可以参考&
如果把这些代码执行一遍,改改调试一下,理解基本流程,那么已经可以写一些提高工作效率的unity插件了
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:8690次
排名:千里之外
转载:32篇
(1)(2)(2)(7)(2)(1)(5)(7)(6)(5)(3)(4)Unity3D自带MonoDevelop编辑器断点调试教程
作者:佚名
字体:[ ] 来源:互联网 时间:11-14 11:56:18
断点调试功能可谓是程序员必备的功能了。Unity3D支持编写js和c#脚本,但很多人可能不知道,其实Unity3D也能对程序进行断点调试的。不过这个断点调试功能只限于使用Unity3D自带的MonoDevelop编辑器
断点调试功能可谓是程序员必备的功能了。Unity3D支持编写js和c#脚本,但很多人可能不知道,其实Unity3D也能对程序进行断点调试的。不过这个断点调试功能只限于使用Unity3D自带的MonoDevelop编辑器。而用Visual Studio是不行的。听说有个叫做UnityVS的东西可以使用VS对Unity进行断点Debug,不过没试过。
好了,简单的说说做法吧:
首先肯定是先要把脚本编辑器指定为MonoDevelop了。
选择好之后,可以在项目面板右键选择Sync&MonoDevelop Project来打开MonoDevelop。
因为需要有脚本才能对脚本进行调试,所以我写了个很简单的脚本,里面有两个按钮,按第一个&add&按钮的时候,程序会用一个循环的方式把从0到9的数加起来,然后累加给sum。按第二个按钮时,会把sum清零。&
写好脚本之后,把脚本随便拖到场景的物体上面,我们准备调试了。在调试之前,我们需要把MonoDevelop和Unity3D进行连接。
具体的连接方法有2种:
第一种,先把当前场景保存一下,然后关掉Unity。回到MonoDevelop,按F5或者点击Debug按钮。
这样,MonoDevelop会打开一个新的Unity3D界面,这时候连接完成了。
第二种方法,无需关掉Unity,在MonoDevelop的Run菜单下选择Attach to Process&
然后选择Unity的进程,点击Attach按钮。
&这时候,MonoDevelop就连接上了Unity了。
当连接好了Unity3D之后,右边的调试按钮就变成可用了,我们把视窗显示选择Debug。
debug模式脚本下面的位置会多出两个窗口。&
回到Unity,点击运行按钮,会看到刚才的脚本已经运行了。里面有两个按钮。&
回到MonoDevelop,在脚本里面我们打一个断点(在行号左边点一下)&
&然后回到Unity里面,点击第一个按钮&add&。这时候断点起作用了,程序会暂停,MonoDevelop跳到断点的行。
留意看下面debug的Locals信息,会看到当前状态下的变量i和sum的值。
使用调试按钮,让程序单步的运行
我们看到了当前的变量i和sum的实际变化情况。
到这里,断点调试已经完成。
调试完之后,我建议最好把MonoDevelop和Unity3D的连接断开。假如你不断开的话,Unity会一直处于很卡的状态。
断开的方法也是有几种了,首先对应Debug按钮有一个断开的按钮,可以直接点击断开。
或者我们可以把刚才附加的进程Detach掉。&
再或者,我们可以点击这个插头按钮,把Debugger 断开。
这两种方法连接Unity,我建议还是使用第二种附加进程的方式吧。毕竟你不可能每次调试都要关掉一次Unity然后再从MonoDevelop打开一次Unity。所以,编写脚本的时候,把连接Detach掉,等需要调试的时候,再把进程Attach上去,进行调试就行了。
大家感兴趣的内容
12345678910
最近更新的内容

我要回帖

更多关于 gta5地图编辑器没反应 的文章

 

随机推荐