我正在尝试创建自己的状态机,但是遇到有关泛型类的列表的麻烦。我的代码如下。
State.cs:
using UnityEngine;
using System.Collections;
public abstract class State<T> where T:StateMachine
{
public T sm;
public State()
{
}
public virtual void OnEnter()
{
sm.currentState = sm.futureState;
}
public abstract void OnExit();
public abstract void OnLoop();
}
StateMachine.cs:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public abstract class StateMachine : MonoBehaviour
{
public List<State<T>> stateList = new List<T>>();
public int currentState = -1;
public int futureState;
protected virtual void Start()
{
foreach (State<T> s in stateList)
{
s.sm = this;
}
}
protected virtual void Update()
{
if (currentState != futureState)
{
stateList[futureState].OnEnter();
}
stateList[currentState].OnLoop();
if (currentState != futureState)
{
stateList[currentState].OnExit();
}
}
}
TestStateMachine.cs:
using UnityEngine;
using System.Collections;
public class TestStateMachine : StateMachine
{
public enum StateNames:int
{
State1,
State2,
};
public KeyCode kc;
// Use this for initialization
protected override void Start ()
{
stateList.Add(new TestStateMachineFirstState());
stateList.Add(new TestStateMachineSecondState());
base.Start();
}
}
public class TestStateMachineFirstState : State<StateMachine>
{
public override void OnEnter()
{
Debug.Log("SM1 OnEnter");
base.OnEnter();
}
public override void OnLoop()
{
Debug.Log("SM1 OnLoop");
if (Input.GetKeyDown(sm.kc))
{
sm.futureState = (int)TestStateMachine.StateNames.State2;
}
}
public override void OnExit()
{
Debug.Log("SM1 OnExit");
}
}
public class TestStateMachineSecondState : State<StateMachine>
{
public override void OnEnter()
{
Debug.Log("SM2 OnEnter");
base.OnEnter();
}
public override void OnLoop()
{
Debug.Log("SM2 OnLoop");
if (Input.GetKeyDown(sm.kc))
{
sm.futureState = (int)TestStateMachine.StateNames.State1;
}
}
public override void OnExit()
{
Debug.Log("SM2 OnExit");
}
}
我收到错误CS0246: Type or namespace name T cannot be found
(或听起来类似的内容)。
如果我将所有State<T>
和State<TestStateMachine>
替换为State<StateMachine>
,将(Input.GetKeyDown(sm.kc))
替换为(Input.GetKeyDown(KeyCode.A))
,我的状态机将“起作用”。
但这并不理想,因为我无法从子状态机中获取变量。有没有办法保持这种结构(尽可能糟糕),或者我应该尝试另一种方法来做状态机?
答案 0 :(得分:1)
有人可能会注意到,如果查看编译器错误消息,它将指定源文件和检测到错误的行号。这通常有助于确定问题。
问题在于:
public abstract class StateMachine : MonoBehaviour
{
public List<State<T>> stateList = new List<T>>();
...
T
在此课程中没有任何意义,因为它不是通用的类或方法。因此,编译器不知道如何处理State<T>
或List<T
。
第二个问题是
public List<State<T>> stateList = new List<T>>();
即使在合适的通用类或方法中,也不会编译:{{1}}不是与List<State<T>>
兼容的类型。
答案 1 :(得分:0)
您收到此编译错误的原因是您在T
类中使用类型State
的类型参数StateMachine
。您可以使用curiously recurring template pattern:
class State<T> where T : StateMachine
class StateMachine<T> where T : StateMachine
class RealStateMachine : StateMachine<RealStateMachine>
然而,这可能会令人困惑。如果能够,则应考虑State是非泛型抽象类或接口的设计。