Unity接口序列化和选择

问题描述 投票:0回答:1

我最近获得了Odin Inspector这个资产,它非常棒,我觉得可以帮助解决这个问题。

我在游戏中实现了一个场景系统,它就像一棵节点树一样。

nodetree

我的实现可能不是最好的,但我认为它适合我们的需要。

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播放模式或任何东西时,它没有被序列化保存。基本上我想要完全一样的东西,但是要保存。

下面是一个简单的视频,展示了这一点。

https:/youtu.berkf9nS2Mz_0

一切都很好,但 "条件 "从来没有保存。

c# unity3d
1个回答
© www.soinside.com 2019 - 2024. All rights reserved.