Unity 2020.1中无法为State的StateLogic属性赋值子类对象的问题
嘿,我完全懂你搜了一小时没找到答案的挫败感——这种卡壳在Inspector赋值的问题,有时候就是序列化的小细节在搞鬼。咱们来一步步搞定这个“可插拔AI”架构里的StateLogic赋值问题。
问题根源
你的核心问题在于:Unity的Inspector默认对抽象ScriptableObject的多态引用支持不够友好,再加上属性定义的序列化细节,导致子类实例没法拖拽到父类字段里。不管是用带[field: SerializeField]的虚拟属性,还是直接public字段,都没触发Unity正确识别子类引用的逻辑。
具体解决方案
方案1:用[SerializeReference]支持多态序列化(推荐)
Unity 2020.1已经支持[SerializeReference]属性,它专门用来处理多态引用类型的序列化,完美适配你的ScriptableObject子类场景。修改你的State类代码:
public class State : ScriptableObject { // 替换原来的虚拟属性,用SerializeReference标记 [SerializeReference] public StateLogic stateLogic; public Action[] actions; public Transition[] transitions; }
同时,给所有StateLogic子类加上[CreateAssetMenu],方便你在Project窗口创建实例:
[CreateAssetMenu(fileName = "IdleStateLogic", menuName = "State Logics/Idle")] public class IdleStateLogic : StateLogic { public void Enter(UnitStateController c) { Debug.Log("Enter IdleStateLogic"); } }
这样修改后,打开你的State实例的Inspector:
- 你会看到
stateLogic字段旁边有个下拉菜单,能直接创建新的IdleStateLogic实例,或者拖拽已有的实例进去 SerializeReference会自动处理多态类型,确保子类实例被正确序列化和识别
方案2:调整字段定义+清理Unity缓存(应急)
如果不想用SerializeReference,可以试试简化字段定义,再清理Unity的缓存:
- 把
State类里的属性改成普通public字段:
public class State : ScriptableObject { public StateLogic stateLogic; public Action[] actions; public Transition[] transitions; }
- 给
StateLogic子类加上[CreateAssetMenu](和方案1一样) - 清理Unity缓存:
- 关闭Unity编辑器
- 删除项目根目录下的
Library文件夹 - 重新打开项目,等待编译完成
这一步是为了解决Unity有时候缓存了旧的序列化数据,导致字段识别异常的问题。
方案3:避免用虚拟属性的序列化陷阱
你之前用的[field: SerializeField] public virtual StateLogic stateLogic { get; set; }之所以不行,是因为Unity对自动属性的序列化支持有局限性:
- 带
virtual的自动属性会生成一个私有后备字段,但这个字段可能没被Unity的序列化系统正确识别 - 直接用普通字段或者
SerializeReference标记的字段,能绕过这个陷阱
验证步骤
- 右键Project窗口,创建一个
IdleStateLogic实例(通过你加的CreateAssetMenu路径) - 创建或打开一个
State实例 - 尝试把
IdleStateLogic实例拖拽到stateLogic字段里,或者通过下拉菜单选择 - 运行游戏,检查
stateLogic是否能正常调用子类的方法
试试看这些方法,应该能解决你的拖拽赋值问题。如果还是有问题,检查下脚本有没有编译错误,或者考虑升级到Unity 2020.1的后续补丁版本(早期版本可能存在小的序列化bug)。
内容的提问来源于stack exchange,提问作者Sciguy77

