我有四个类,Event
和Action
都是基类,然后有两个子类Create : Event
和MoveTo : Action
。
Event
包含一个Action
实例的列表,当在子Trigger()
中调用Create
时,它将调用Event.Trigger()
,该列表遍历操作,并在调用Action.Run()
的每个操作上调用Called()
。
我遇到的问题是调用virtual
方法,而不是override
内部的MoveTo
方法。
[Serializable]
public abstract class Event : MonoBehaviour {
[SerializeField] public List<Action> actions = new List<Action>();
protected void Trigger() {
foreach (Action action in actions) {
action.Run();
}
}
}
事件
public class Create : Event {
void Start() {
Trigger();
}
}
动作
[Serializable]
public class Action {
public virtual void Called() {
Debug.Log("Virtual");
}
public void Run() {
Called();
}
}
MoveTo
public class MoveTo : Action {
public override void Called() {
Debug.Log("Called");
}
}
我正在将MoveTo
操作从Unity Editor的事件列表添加到预制上。我不确定运行时如何统一处理这些,是初始化它们还是执行?我不确定。那可能是导致我的问题的原因...
private Event GetCurrentEvent(){}
void AddActionCallback(Type actionType) {
// actionType is MoveTo
var prefab = GetCurrentPrefabItem().Value;
var evt = GetCurrentEvent();
evt.actions.Add((Action)Activator.CreateInstance(actionType));
Undo.RecordObject(prefab.gameObject, "Added actions");
PrefabUtility.RecordPrefabInstancePropertyModifications(prefab.gameObject);
}
这是运行游戏之前的外观。它显示MoveTo
,红色栏中的按钮显示使用action.GetType().Name
的操作。这是我运行游戏之前的名称:
运行游戏后,按钮现在如下所示:
运行时:
evt.actions.Add((Action)Activator.CreateInstance(actionType));
即使actionType
和Activator.CreateInstance(actionType)
的输出为MoveTo
,编辑器也会显示类型不匹配:
答案 0 :(得分:1)
保存预制件时,它会将List序列化为纯Action
的列表,并删除仅子类MoveTo
拥有的所有信息。
来自Unity docs on serialization:
不支持多态性
如果您有
public Animal[] animals
并且 您将Dog
,Cat
和Giraffe
的实例放在 序列化,您有三个Animal
的实例。处理此限制的一种方法是认识到它仅 适用于自定义类,该类可以内联序列化。参考 其他
UnityEngine.Objects
被序列化为实际引用,并且对于 这些,多态性确实有效。你会做一个ScriptableObject
派生类或另一个MonoBehaviour
派生类, 并参考。缺点是您需要存储Monobehaviour
或scriptable
的某个地方,而您不能 有效地内联序列化它。这些限制的原因是核心基础之一 序列化系统的特点是 提前知道一个物体;这取决于类型 类的字段,而不是存储在 字段。
这就是为什么其类显示为Action
的原因。
但是,它不能序列化为Action
because:
如何确保自定义类可以序列化
确保:
具有Serializable属性
不是抽象
不是静态的
不是通用类,尽管它可能继承自通用类
Action
是一个抽象类,因此它甚至无法部分正确地序列化。我认为这是Type Mismatch
问题的根本原因,因为Unity正在努力反序列化一些不受支持的内容。
简而言之,如果要序列化MoveTo
中的数据,则需要有一个[SerializeField]
List<MoveTo>
,以免丢失信息,或者可以使Action继承来自ScriptableObject
,带来了自己的问题。