Unity下通过代码修改prefab的参数


问题
做Unity开发时,经常需要写一些Editor代码,用来提高开发的效率,常见的一种情况就是通过代码修改场景里Prefab的参数。一般修改后会发现一切如期望般正常,但一旦你重启Unity,或者重新加载Scene,那么就会惊喜地发现,之前做出的修改都没有生效。
由于我习惯使用新版的Unity,所以下面都是基于Unity 2019版本,其他版本是否会有这个问题,能不能用这种方式解决,就各自尝试了。

原因
假设我们有一个简单的脚本,如下

using UnityEngine;

public class Test : MonoBehaviour
{
public int Value;
}

我们把它挂接在一个空的GameObject下,做成一个Prefab,如下:

如果我们直接在Editor下修改Value的值,如下图,可以看到Value左边有一条蓝色的长条,同时Value和3都变成了粗体。(细心的读者还会注意到,Unity的标题栏最后会多了个表示Scene修改的*)

这是因为我们不是直接修改Prefab,而是在Prefab上做了一个Override。关于Override,可以理解为是一个盒子,盒子里面是它对应的Prefab,而我们的修改是修改了Override,而没有直接修改到Prfab,所以不会影响其他同一个Prefab的值。当Unity要获取Prefab的参数时,会优先找这个参数有没有被Override,有的话就用Override的值,没有则用Prefab的值。
注意就算我们把Value的值改为0,Override还是生效了,可以通过Ctrl+z撤销之前的操作,可以看到Override消失了。
我们写一个简单的Editor代码来实验下通过代码直接修改Value的值,如下:

[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();

var test = target as Test;
if (GUILayout.Button("Change")) {
test.Value = UnityEngine.Random.Range(1, 100);
}}}

这时候如果你点击Change按钮,会发现Value的值确实修改了,但没有了表示Overide的蓝条,文字没有变成粗体(标题栏的*号也没了),而且你按Ctrl+z是无法撤销这次修改的。更糟糕的是,你重启Unity后会发现值并没有生效。

这是因为Unity并不知道我们做出了修改,所以没有帮我们保存这次修改。

解决
解决方法有几种,但最推荐的是采用Undo,如下:

[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();

var test = target as Test;
if (GUILayout.Button("Change")) {
Undo.RecordObject(test, "modify test value");
test.Value = UnityEngine.Random.Range(1, 100);
EditorUtility.SetDirty(test);
}}}

再次点击Change按钮,会发现和直接在Editor修改的结果是一致的。Ctrl+z也能生效。那么Undo.RecordObject的第二个参数是干嘛的?你打开菜单栏的Edit菜单会有惊喜。

友情提示,如果是一次修改大量的Prefab,可以采用Undo.RecordObjects。
友情提示2,Undo.RecordObject有时会失效,这个函数好像不太可靠,更可靠的方法是在最后加上EditorUtility.SetDirty()。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM