C# 需要使用继承在有限状态机中接受派生类型参数的帮助吗
我刚刚开始尝试使用一些抽象类和继承来编写一个有限状态机,其中状态和状态机可以被继承,这样框架就可以用于不同类型的AI 问题是继承的类一直期望其参数的基类型,而不接受派生类型,我不确定我是以错误的方式进行操作,还是仅仅以错误的方式进行编码。(据我所知,我正在努力实施) 基本代码:C# 需要使用继承在有限状态机中接受派生类型参数的帮助吗,c#,inheritance,unity3d,polymorphism,abstract,C#,Inheritance,Unity3d,Polymorphism,Abstract,我刚刚开始尝试使用一些抽象类和继承来编写一个有限状态机,其中状态和状态机可以被继承,这样框架就可以用于不同类型的AI 问题是继承的类一直期望其参数的基类型,而不接受派生类型,我不确定我是以错误的方式进行操作,还是仅仅以错误的方式进行编码。(据我所知,我正在努力实施) 基本代码: public abstract class State { public abstract void BeginState(StateMachine stateMachine); public abstr
public abstract class State {
public abstract void BeginState(StateMachine stateMachine);
public abstract void UpdateState(StateMachine stateMachine);
public abstract void EndState(StateMachine stateMachine);
}
public class StateMachine : MonoBehaviour {
//Stuff here to execute the current state, store previous state, revert states, etc.
//Example:
private State currentState;
private State previousState;
public virtual void SwitchState(State newState) {
//Switch state, store previous state if not null
if (currentState != null) {
previousState = currentState;
currentState.EndState(this);
}
currentState = newState;
currentState.BeginState(this);
}
}
这个想法是,这些可以被继承和扩展,为人类ai、僵尸ai、机器人ai等工作:
public class Idle : State
{
//Begin, Update, and End states here. Example:
public override void BeginState(ZombieStateMachine ZSM)
{
Debug.Log("Begin idling");
}
}
public class ZombieStateMachine : StateMachine {
public Idle idleState = new Idle();
void Start {
SwitchState(idleState);
}
}
从抽象状态类继承的空闲状态会出现问题。我试图通过ZombieStateMachine,它继承了StateMachine,但是Idle类抛出一个错误,并期望使用StateMachine。(编辑:该错误是编译时错误,而不是我错误地暗示的运行时错误)
非常感谢您的帮助。这是您描述的运行时错误吗?或者这是一个编译时错误?我怀疑是后者,因为:
public override void BeginState(ZombieStateMachine ZSM)
实际上并没有覆盖这一点:
public abstract void BeginState(StateMachine stateMachine)
覆盖需要是相同的类型:
public override void BeginState(StateMachine ZSM)
在这种情况下,Liskov替换原则的思想是,begintate
方法中的任何内容都不应该关心给定的StateMachine
类型,它应该只与基本StateMachine
操作交互
两个基类都互相传递,这似乎有点奇怪。State
上的方法需要一个StateMachine
,而StateMachine
上的方法需要一个State
。现在还不清楚为什么会这样
但是,如果确实需要这样做,那么我想知道您是否可以从泛型基类型中获益。大概是这样的:
public abstract class State<T> where T : StateMachine
{
public abstract void BeginState(T stateMachine);
public abstract void UpdateState(T stateMachine);
public abstract void EndState(T stateMachine);
}
公共抽象类状态,其中T:StateMachine
{
公开摘要无效开始(T状态机);
公共抽象资产(T状态机);
公共抽象void EndState(T状态机);
}
然后使用指定的类型继承:
public class Idle : State<ZombieStateMachine>
{
//Begin, Update, and End states here. Example:
public override void BeginState(ZombieStateMachine ZSM)
{
Debug.Log("Begin idling");
}
}
公共类空闲:状态
{
//此处的开始、更新和结束状态。示例:
公共覆盖void BeginState(ZombieStateMachine ZSM)
{
Log(“开始空转”);
}
}
这是写意代码,所以我不是100%确定它是否有效,但对我来说似乎是合理的。(如果不正确,我将继续删除此答案。)
这种类型限制了您尝试的纯多态性,因为子类型不能再接受任何实现基类型的类型。但看起来这正是您从使用中所期望的,一个类的给定子类型实际上将与另一个类的相应子类型“配对”。通过使用泛型,它们可以显式配对。请详细说明您希望在方法声明中使用
ZombieStateMachine
而不是StateMachine
。事实上,正如编译器所说,您必须使用被重写方法的确切方法签名;这里只允许使用StateMachine
。但是使用抽象/多态性等的目的是让调用方不必知道所使用对象的实际实现类型。如果希望对传递给对象的类型有编译时限制,那么使用多态方法可能不适合您。提供更多关于您真正目标的详细信息在这里会有所帮助。我想使用ZombieStateMachine
而不是StateMachine
的原因是所有状态机都将使用该框架,但ZombieStateMachine
脚本内部也将是唯一的僵尸状态类,如HuntPlayer
,Idle
,grampobject
但也在ZombieStateMachine
中是移动僵尸所需的变量,因此NavMeshAgent
,ZombieThirdPersonAnimator
等等。我认为这种多态方法将减少我必须重复的代码量,因为否则我必须为每种不同的AI类型重复完全相同的StateMachine
代码。你能发布例外情况吗?来自Unity:“资产/_脚本/_Zombies/ZombieStateMachine.cs(55,26):错误CS0115:`Idle.begintate”(ZombieStateMachine)“”标记为重写,但找不到可重写的合适方法”一些建议:你的状态机应该只是这样。它应该维护state.Period。让其他类在状态机报告状态并做出相应响应时使用状态。这样,你的僵尸特定代码就根本不是一个状态机,而只是组成一个状态机。状态机应该严格地接受输入,ap应用到当前状态,并确定新状态。使用correct,您的类型冲突问题将消失。很抱歉,您是正确的,这是一个编译时错误。(我将查看您的代码是否适用于我。)我尝试了你的代码。我遇到了一个问题,在使用状态声明的StateMachine内部,它现在也需要为这些声明指定一个类型。例如,public void SwitchState(State newState){}
,当从ZSM
作为SwitchState(idlstate)
调用时,它不再工作(因为我猜idlstate是ZSM类型的?)@Visulth:啊,你说得对。这会产生一种循环依赖。我想这可以追溯到问题……为什么两个基类型都需要相互引用?我希望一个引用另一个,但不是两个都互相引用。为什么需要为St上的方法提供StateMachine
ate
?我希望一个“状态”本身是一个离散的东西,“状态机”会对一组状态执行操作。好吧,也许我说的不对