模拟游戏中怪物巡航的模块,当怪物靠近玩家小于15米时,进入追踪玩家状态。当怪物离玩家30米以上时,重新进入巡航状态。输入玩家与怪物之间的距离,求出怪物的状态。
输入第一行给出一个正整数n(n⩽10)表示距离更新的批次。随后n行,每行给出1个整数(距离)。
输出n次怪物的状态。
输入样例
3
31
14
13
输出样例:
巡逻状态持续中
进入追击状态
追击状态持续中
有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机(英语:finite-state automaton,缩写:FSA),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型。
在实际开发过程中,我们经常需要处理各种状态的切换,一般情况下我们用if…else if…或者switch case 就可以解决。但是在遇到一些比较复杂的逻辑,需要很多的状态,并且有一些状态还要处理一些复杂的逻辑,这个时候再用上面的方法就显得有点捉襟见肘了,严重影像后期的维护。有限状态机就是为了解决这种多状态切换的一种数学模型。
设计有限状态机的要素 状态机可归纳为4个要素,即现态、条件、动作、次态。“现态”和“条件”是因,“动作”和“次态”是果。
详解如下:
①现态:是指当前所处的状态。
②条件:又称为“事件”。当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
定义两个枚举类型
Transition表示状态过度需要的条件(看见敌人,失去敌人)
StateID表示状态的ID。
public enum Transition
{
NullTransition = 0, // 使用此过渡来表示系统中不存在的过渡
SawPlayer = 1,//看见敌人
LostPlayer//失去敌人
}
public enum StateID
{
NullStateID = 0, // 使用此ID表示系统中不存在的状态
FollowingPath = 1,//巡航状态ID
ChasingPlayer //追踪状态ID
}
定义一个有限状态机
class FSMSystem
{
//用List来存储所有的状态
private List<FSMState> states;
// 当前激活的状态对象和对应的ID
private StateID currentStateID;
private FSMState currentState;
public StateID CurrentStateID { get { return currentStateID; } }
public FSMState CurrentState { get { return currentState; } }
//构造函数中,创建一个状态列表对象
public FSMSystem()
{
states = new List<FSMState>();
}
/// 添加状态的方法.
public void AddState(FSMState s)
{
if (s == null)
{
Console.WriteLine("FSM ERROR: Null reference is not allowed");
}
//插入的第一个状态是初始状态,并将该状态放置List集合中
if (states.Count == 0)
{
states.Add(s);
currentState = s;
currentStateID = s.ID;
return;
}
//遍历循环所有的状态,将List集合中存在的状态ID和传进来的状态ID比较
foreach (FSMState state in states)
{
if (state.ID == s.ID)
{
Console.WriteLine("FSM ERROR: 不能添加 " + s.ID.ToString() +
" 因为此状态已经存在");
return;
}
}
states.Add(s);
}
public void DeleteState(StateID id)
{
//如果当前的状态ID为空ID,则不能删除状态ID
if (id == StateID.NullStateID)
{
Console.WriteLine("FSM ERROR: NullStateID is not allowed for a real state");
return;
}
//遍历循环List集合中的状态ID,如果传进来的id存在List集合中,则可以进行移除
foreach (FSMState state in states)
{
if (state.ID == id)
{
states.Remove(state);
return;
}
}
Console.WriteLine("FSM ERROR: 不能删除 " + id.ToString() +
". 此状态不在列表中");
}
///
/// 执行状态转换的方法
///
public void PerformTransition(Transition trans)
{
//在状态转化前判断Transition是否为NullTransition
if (trans == Transition.NullTransition)
{
Console.WriteLine("FSM ERROR: NullTransition is not allowed for a real transition");
return;
}
//根据当前状态的条件获取当前状态的ID
StateID id = currentState.GetOutputState(trans);
if (id == StateID.NullStateID)
{
Console.WriteLine("FSM ERROR: State " + currentStateID.ToString() + " does not have a target state " +
" for transition " + trans.ToString());
return;
}
//更新当前的状态和状态ID
currentStateID = id;
foreach (FSMState state in states)
{
if (state.ID == currentStateID)
{
//在设置新状态之前对状态进行处理
currentState.DoBeforeLeaving();
currentState = state;
//将状态重置为所需状态,然后再进行推理或操作
currentState.DoBeforeEntering();
break;
}
}
}
}
抽象状态类
public abstract class FSMState
{
protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();//条件列表
protected StateID stateID;//状态ID,唯一
public StateID ID { get { return stateID; } }
public void AddTransition(Transition trans, StateID id)//添加条件方法
{
if (trans == Transition.NullTransition)
{
Console.WriteLine("FSMState ERROR: NullTransition is not allowed for a real transition");
return;
}
if (id == StateID.NullStateID)
{
Console.WriteLine("FSMState ERROR: NullStateID is not allowed for a real ID");
return;
}
if (map.ContainsKey(trans))
//检查当前的过度条件是否存在map集合中
{
Console.WriteLine("FSMState ERROR: State " + stateID.ToString() + " already has transition " + trans.ToString() +
"Impossible to assign to another state");
return;
}
map.Add(trans, id);
}
///
/// 从列表中删除条件的方法
/// 如果过度条件不存在map集合中,打印错误信息
///
public void DeleteTransition(Transition trans)
{
if (trans == Transition.NullTransition)
{
Console.WriteLine("FSMState ERROR: NullTransition is not allowed");
return;
}
if (map.ContainsKey(trans))
{
map.Remove(trans);
return;
}
Console.WriteLine("FSMState ERROR: Transition " + trans.ToString() + " passed to " + stateID.ToString() +
" was not on the state's transition list");
}
public StateID GetOutputState(Transition trans)
{
//根据过度条件返回一个stateID
if (map.ContainsKey(trans))
{
return map[trans];
}
return StateID.NullStateID;
}
public virtual void DoBeforeEntering() { }
public virtual void DoBeforeLeaving() { }
public abstract void Reason(int meters);
public abstract void Act();
}
实现抽象状态类
class FollowPathState : FSMState//巡逻状态
{
private FSMSystem sys;
public FollowPathState(FSMSystem sys)
{
stateID = StateID.FollowingPath;
this.sys = sys;
}
public override void Reason(int meter)
{
if (meter < 15)
{
//条件转变,看见目标
sys.PerformTransition(Transition.SawPlayer);
Console.WriteLine("进入追击状态");
}
else
{
Console.WriteLine("巡逻状态持续中");
}
}
public override void Act() { }
}
class ChasePlayerState : FSMState//追踪状态
{
private FSMSystem sys;
public ChasePlayerState(FSMSystem sys)
{
stateID = StateID.ChasingPlayer;
this.sys = sys;
}
public override void Reason(int meter)
{
if (meter >= 30)
{
//条件改变,丢失目标
sys.PerformTransition(Transition.LostPlayer);
Console.WriteLine("进入巡逻状态");
}
else
{
Console.WriteLine("追击状态持续中");
}
}
public override void Act() { }
}
客户端实现
static void Main(string[] args)
{
//创建一个有限状态机-->创建了一个状态列表
FSMSystem fsmSystem = new FSMSystem();
//创建怪物的状态
FollowPathState followPathState = new FollowPathState(fsmSystem);
followPathState.AddTransition(Transition.SawPlayer, StateID.ChasingPlayer);
ChasePlayerState chasePlayerState = new ChasePlayerState(fsmSystem);
chasePlayerState.AddTransition(Transition.LostPlayer, StateID.FollowingPath);
fsmSystem.AddState(followPathState);//将巡逻状态添加到有限状态机中
fsmSystem.AddState(chasePlayerState);//将追击状态添加到有限状态机中
int n=Convert.ToInt32(Console.ReadLine());
for(int i = 0; i < n; i++)
{
int meters=Convert.ToInt32(Console.ReadLine());
//状态改变的原因
fsmSystem.CurrentState.Reason(meters);
//结果
fsmSystem.CurrentState.Act();
}
}
本篇到此结束!