能否在ScriptableObject中使用UnityEvents/UnityActions并引用层级GameObject?
当然可以啦!我来分两部分给你解答这两个问题:
1. ScriptableObject中使用UnityEvents/UnityActions完全可行
你写的代码本身是完全正确的——UnityEvent和UnityAction在ScriptableObject里是支持序列化的,编辑器里能正常显示这个事件字段,还能直接在Inspector面板中添加回调方法。
不过有几个要注意的点:
- 如果你的UnityEvent绑定了场景中的组件方法,当场景卸载后这些绑定会失效(因为场景对象被销毁了)
- 如果需要让ScriptableObject的回调在跨场景时依然有效,建议绑定到单例对象或者资源文件夹中预制体的组件(运行时实例化的那种),这类对象不会随场景卸载被销毁
- 要是需要带参数的回调,直接用泛型版本的UnityEvent就行,比如
public UnityEvent<string> OnDogSpoke;,用法和普通UnityEvent完全一致
2. ScriptableObject持有GameObject引用的两种情况
ScriptableObject可以持有GameObject引用,但要分场景对象和预制体两种情况来看:
- 引用资源文件夹中的预制体:完全没有问题,序列化和反序列化都正常,运行时也能正确加载,非常适合用来存储需要复用的对象模板
- 引用场景层级中的GameObject:编辑器里能看到引用,但有不少坑:
- 场景卸载后,这个引用会直接变成
null,因为场景对象已经被销毁了 - 把ScriptableObject打包成AssetBundle时,场景对象的引用会丢失(场景对象不属于AssetBundle的资源范畴)
- 如果确实需要引用场景对象,建议在运行时通过代码动态赋值(比如在场景初始化时用
GameObject.Find()或者单例模式找到对象后赋值),而不是在编辑器里直接拖,这样能避免意外的空引用问题
- 场景卸载后,这个引用会直接变成
你的示例代码可以正常运行,这里再贴出来方便参考:
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; [CreateAssetMenu(menuName ="Dog", fileName ="New Dog")] public class Dog : ScriptableObject { public string Id; public string Text; public UnityEvent WhenFinished; public GameObject Go; }
总的来说,你的写法本身是没问题的,只要注意场景对象引用的局限性就行。如果是做跨场景复用的配置,优先用预制体引用,回调绑定到持久化的对象上会更稳妥~
内容的提问来源于stack exchange,提问作者Daarwin
相关产品推荐
相关产品推荐

