Unity中ScriptableObject内抽象类bool变量默认值失效如何解决
Unity任务系统条件判断模块问题解决方案
所有问题均和Unity序列化机制、ScriptableObject资产特性、引用类型赋值逻辑有关,和抽象类无关。
问题原因拆解
- 可序列化类初始值被忽略:Unity对标记
[Serializable]的类实例执行序列化时,字段的C#代码初始值会被序列化文件中存储的历史值覆盖,代码声明时的默认赋值不会生效。如果conditionMet曾经被运行时修改为true并被序列化保存,后续加载时就会返回true。 - 运行时修改同步影响ScriptableObject:你在创建Quest实例时直接引用了ScriptableObject中存储的Condition实例,引用类型赋值传递的是内存地址,修改Quest中的Condition字段本质就是修改ScriptableObject资产中的原对象,Unity会自动持久化ScriptableObject的改动,导致运行时状态被保存。
解决方案
1. 禁止序列化运行时状态字段
给conditionMet添加[NonSerialized]特性,让Unity完全忽略该字段的序列化,代码中的初始值= false就会正常生效,同时该字段的改动不会被保存到ScriptableObject资产中。
2. 实例化Quest时深拷贝Condition配置
给Condition抽象类添加克隆方法,每个子类实现深拷贝逻辑,创建Quest实例时复制所有Condition的配置字段生成新实例,实现运行时实例和ScriptableObject配置的隔离,避免修改原资产。
修改后代码示例
public abstract class Condition { [SerializeField] protected string parameter; public string Parameter => parameter; // 禁止序列化运行时状态,代码初始值生效 [System.NonSerialized] protected bool conditionMet = false; public bool ConditionMet => conditionMet; public abstract void CheckCondition(string eventMessage); // 抽象克隆方法,用于深拷贝配置 public abstract Condition Clone(); } [System.Serializable] public class IntCondition : Condition { [SerializeField] private NumberComparisonType comparison; [SerializeField] private int expectedInt; public override void CheckCondition(string eventMessage) { int count = int.Parse(eventMessage.Split(':')[1]); conditionMet = comparison switch { NumberComparisonType.GreaterOrEqual => count >= expectedInt, NumberComparisonType.Less => count < expectedInt, _ => conditionMet }; } public override Condition Clone() { return new IntCondition() { parameter = this.parameter, comparison = this.comparison, expectedInt = this.expectedInt }; } }
Quest实例化示例代码
public class Quest { public List<Condition> RuntimeConditions { get; private set; } public Quest(QuestData questData) { // 深拷贝所有条件配置,和SO原资产隔离 RuntimeConditions = questData.Conditions.Select(cond => cond.Clone()).ToList(); } }
内容的提问来源于stack exchange,提问作者ademakyazici
相关产品推荐
相关产品推荐

