我最近获得了Odin Inspector这个资产,它非常棒,我觉得可以帮助解决这个问题。
我在游戏中实现了一个场景系统,它就像一棵节点树一样。
我的实现可能不是最好的,但我认为它适合我们的需要。
public class ScenarioManager : MonoBehaviour
{
public static ScenarioManager Instance { get; private set; }
public Scenario CurrentScenario { get; private set; }
[SerializeField] private Scenario scenario;
private void Awake()
{
Instance = this;
// TODO : DEBUG : load accordingly
LoadScenario(scenario);
}
private void Update()
{
int nextState = CurrentScenario.CurrentState.MoveNext();
if (nextState == -1) return;
CurrentScenario.Transition(CurrentScenario.CurrentState.transitions[nextState]);
}
private void LoadScenario(Scenario toLoad)
{
CurrentScenario = toLoad;
CurrentScenario.StartScenario();
}
}
public class Scenario : MonoBehaviour
{
public ScenarioState CurrentState { get; private set; }
[SerializeField] private string scenarioName;
[SerializeField] private ScenarioState initialState;
public void LoadState(ScenarioState state)
{
CurrentState = state;
if (CurrentState == null)
{
// TODO : scenario end
Debug.Log("Next state is null : scenario finished or missing transition", this);
return;
}
print($"Entering state '{CurrentState.stateName}'");
}
public void Transition(StateTransition transition)
{
transition.transitionEvents.Invoke();
LoadState(transition.state);
}
public void StartScenario()
{
print($"Starting scenario '{scenarioName}'");
LoadState(initialState);
}
}
在我的图中,一个 "状态 "就是一个矩形
public class ScenarioState : SerializedMonoBehaviour
{
public string stateName;
public StateTransition[] transitions;
public int MoveNext()
{
for (int i = 0; i < transitions.Length; i++)
{
if (transitions[i].Condition)
{
return i;
}
}
return -1;
}
}
一箭双雕
[Serializable]
public class StateTransition
{
public ScenarioState state;
// Here is what I cannot figure out how to do
[OdinSerialize]
public ITransitionCondition[] conditions;
[Serializable] public class TransitionEvents : UnityEvent {}
public TransitionEvents transitionEvents = new TransitionEvents();
public bool Condition => CheckCondition();
private bool CheckCondition()
{
for (int i = 0; i < conditions.Length; i++)
{
if (!conditions[i].Condition) return false;
}
return true;
}
}
所以,我有一个ITransitionCondition数组,这是一个非常基本的接口,持有一个bool,如果过渡中的每一个条件为真,那么过渡就可以发生。
public interface ITransitionCondition
{
bool Condition { get; }
}
下面是一个简单的例子,只是在等待一个定时器。
[Serializable]
public class TransitionConditionTimer : ITransitionCondition
{
public bool Condition => TimerCheck();
[SerializeField] private float timeToWait;
private float _timer;
private bool TimerCheck()
{
_timer += Time.deltaTime;
return _timer >= timeToWait;
}
}
所以,我想实现的是,有一个下拉菜单,我可以在其中添加remove ITransitionCondition的实现,但我找不到一个方法来实现它。我可以使用Odin的[ShowInInspector]属性来实现,但是当我进入quit播放模式或任何东西时,它没有被序列化保存。基本上我想要完全一样的东西,但是要保存。
下面是一个简单的视频,展示了这一点。
一切都很好,但 "条件 "从来没有保存。