【问题标题】:How to edit a MonoBehaviour's properties on a prefab in the UnityEditor from Script如何从脚本在 Unity 编辑器中编辑预制件上的 MonoBehaviour 属性
【发布时间】:2016-12-11 15:43:24
【问题描述】:

假设我有一个简单的MonoBehaviour

public class FooScript : MonoBehaviour {
  public int someValue = 0;
}

我制作游戏对象,附上FooScript。我从中制作了一个预制件并在场景中删除实例。

在编辑器中,我可以选择项目中的预制件,我可以编辑someValue

假设我知道预制件的路径,我如何制作一个编辑时间脚本来编辑预制件内的FooScript 实例?

尝试了什么

GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(pathToPrefab);
GameObject root = ???? // WHAT DO I CALL HERE!?
FooScript fooScript = root.GetComponent<FooScript>();
fooScript.someValue = 789;

其实在那种情况下prefab 是空的

如果切换到

Object prefab = AssetDatabase.LoadMainAssetAtPath(prefabPath);                 
GameObject root = prefab as GameObject;

prefab 不为空,但root

接下来我尝试了这个

Object[] objs = AssetDatabase.LoadAllAssetsAtPath(prefabPath);
foreach (var o in obs)
{
   Debug.Log("    type:" + (o.GetType().Name));
}

打印出来的

type: GameObject
type: Transform
type: FooScript

但是使用它是一个 hacky 解决方案,因为我必须尝试每个 GameObject 和/或 FooScript。我的意思是我认为作为一个务实的解决方案它可能会起作用,但感觉就像增加了我必须稍后解决的技术债务

我尝试过的其他事情是使用新的 GameObject 和新的 FooScript 创建一个新的预制件并调用 PrefabUtility.ReplacePrefab

GameObject newGameObject = new GameObject();
FooScript fooScript = newGameObject.AddComponent<FooScript>();
fooScript.someValue = 789;

Object prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
PrefabUtility.ReplacePrefab(newGameObject, prefab, ReplacePrefabOptions.ConnectToPrefab);

GameObject.Destory(newGameObject); // don't want this in the scene

但这对我不起作用。预制件中的值被替换,但场景中的所有实例都断开连接。

重申。我不是要编辑预制件的实例。我正在尝试在编辑时从脚本编辑预制件本身。

【问题讨论】:

标签: c# unity3d


【解决方案1】:

只需将加载的对象转换为GameObject

Object prefab = AssetDatabase.LoadAssetAtPath(pathToPrefab, typeof(GameObject));
GameObject root = prefab as GameObject; //a prefab is also just a gameobject
FooScript = root.GetComponent<FooScript>();
root.someValue = 789;

不要忘记保存更改

EditorUtility.SetDirty(prefab)

AssetDatabase.SaveAssets

【讨论】:

  • 这是我尝试的第一件事。根是null 所以没有预制件不是游戏对象:(
  • @gman 你用过AssetDatabase 类吗?因为在您的示例代码中它说Assetroot 的值是多少,因为如果那也是null,那么你的路径可能是错误的。
  • 是的,我使用了AssetDatabase。抱歉,Asset. 打错了。另外,以防万一不是我对您的答案投了反对票。我更新了问题。
  • 我需要打电话给AssetDatabase.SaveAssets吗?或者只是用户只是选择“保存项目”或类似的东西。文档似乎没有说
  • 如果用户保存项目,那么您不需要调用 saveassets
【解决方案2】:
 // this fails
 GameObject prefab = 
    AssetDatabase.LoadAssetAtPath<GameObject>(pathToPrefab));

 // this fails
 GameObject prefab = 
    AssetDatabase.LoadAssetAtPath(pathToPrefab, typeof(GameObject));  

 // this succeeds
 GameObject prefab = 
    AssetDatabase.LoadAssetAtPath(pathToPrefab, typeof(Object)) as GameObject;

【讨论】:

  • 你对第二种解决方案的推理对我来说没有意义。对象只是基类的一个例子。没有任何变化。
  • 我认为因为Object prefab = AssetDatabase.LoadAssetAtPath&lt;GameObject&gt;(prefabPath); 失败了,所以PrefabUtility.ReplacePrefab 会被null 调用。但是这样预制件就不会被替换,所以它确实没有完全的意义。仍然很高兴有一个沟通不畅的解决方案然后:)
  • 哦,是的,我应该再次尝试使用替换。不完全确定这是我想要的,但我会试一试。 See new question :P 也许答案是更换预制件?虽然这实际上很糟糕,因为我必须将所有属性从旧预制复制到新预制,然后修改我的一个字段。嗯:(
  • @ColmanJ 如果您能以任何方式帮助解决这个相关问题,我将不胜感激stackoverflow.com/questions/54201824/…
【解决方案3】:

你需要像这样加载一个游戏对象:

 string prefabPath = "Assets/demo1/Resources/GameObject.prefab";
    Object prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);

别忘了后缀名

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-24
    • 1970-01-01
    • 1970-01-01
    • 2012-01-26
    • 2021-01-25
    • 1970-01-01
    • 2016-12-11
    相关资源
    最近更新 更多