设计模式——有限状态机FSM

前言:在Unity中使用有限状态机(FSM)是管理游戏对象行为(如角色控制、AI逻辑、动画切换)的核心技术之一。在学习阶段,在没学习代码设计原则之前,我们可能把一个玩家所有的行为都在写一个脚本。这样是对于以后的维护来说是十分不利,以后有了新需求,因为都写在一起,代码黏糊糊在一起,牵一发而动全身。所以设计代码要规范,尽量要利于以后维护。
建议先看看下面这个,复习一下
代码设计原则

现在实现一个玩家简易FSM。

设计玩家目前只有二个状态,idle(待机)、move(移动),在代码设计上,根据单一原则,我们将这三个状态分别都设计为一个类,IdeleState,MoveState,二个类。对这个二个分析一下,无论是什么状态都会有进入,执行,退出三部分组成。对于状态公有的行为,提取出一个抽象类

  1. 定义状态抽象类
public abstract class State
{
    // 当前状态进入时调用
    public virtual void Enter()
    {
        Debug.Log("Enter State");
    }

    // 当前状态更新时调用
    public virtual void Update()
    {
        Debug.Log("Update State");
    }

    // 当前状态退出时调用
    public virtual void Exit()
    {
        Debug.Log("Exit State");
    }
}
  1. 创建具体状态
    定义具体的状态类,继承自 State,并实现具体的行为逻辑。
public class IdleState : State
{
    public override void Enter()
    {
        Debug.Log("Enter Idle State");
    }

    public override void Update()
    {
        Debug.Log("Idle State Update");
    }

    public override void Exit()
    {
        Debug.Log("Exit Idle State");
    }
}

public class MoveState : State
{
    public override void Enter()
    {
        Debug.Log("Enter Move State");
    }

    public override void Update()
    {
        Debug.Log("Move State Update");
    }

    public override void Exit()
    {
        Debug.Log("Exit Move State");
    }
}
  1. 有了状态后,我们需要一个专门的一个类,用来专门处理这些状态之间的切换,状态管理器负责管理当前状态,并处理状态切换。
public class StateHandler : MonoBehaviour
{
    
    private State currentState;
    // 切换到指定状态
    public void ChangeState(State newState)
    {
        if (currentState != null)
        {
            currentState.Exit(); // 退出当前状态
        }

        currentState = newState;
        currentState.Enter(); // 进入新状态
    }

    // 在 Update 中调用当前状态的 Update 方法
    private void Update()
    {
        if (currentState != null)
        {
            currentState.Update();
        }
    }
}
  1. 在 Unity 中,将 StateHandler 脚本附加到一个 GameObject 上,并通过代码切换状态。同时新建一个PlayerController用来控制。
public class PlayerController : MonoBehaviour
{
    private StateHandler stateHandler;

    private IdleState idleState;
    private MoveState moveState;

    void Start()
    {
        stateHandler = GetComponent<StateHandler>();
        idleState = new IdleState();
        moveState = new MoveState();

        // 初始状态为 Idle
        stateHandler.ChangeState(idleState);
    }

    void Update()
    {
        // 示例:按下空格键切换到 Move 状态
        if (Input.GetKeyDown(KeyCode.Space))
        {
            stateHandler.ChangeState(moveState);
        }

        // 示例:按下 ESC 键切换回 Idle 状态
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            stateHandler.ChangeState(idleState);
        }
    }
}

至此,一个简易的FSM完成了,看起来就二个状态,一下子写了四个脚本看起来很麻烦,感觉有点小题大做的。那么我们有了新的需求给玩家新加一个状态,比如攻击。这个时候我们只需要新增东西,而不需要修改原本有的东西,这就符合开闭原则。
第一步,新建一个AttackState类

public class AttackState : State
{
    public override void Enter()
    {
        Debug.Log("Enter Move State");
    }

    public override void Update()
    {
        Debug.Log("Move State Update");
    }

    public override void Exit()
    {
        Debug.Log("Exit Move State");
    }
}  

第二步,在PlayerContoller里,添加。

public class PlayerController : MonoBehaviour
{
    private StateHandler stateHandler;

    private IdleState idleState;
    private MoveState moveState;
    //新增攻击状态
    private AttackState attackState;

    void Start()
    {
        stateHandler = GetComponent<StateHandler>();
        idleState = new IdleState();
        moveState = new MoveState();
       //New 新增攻击状态
       attackState = new AttackState();
       
        // 初始状态为 Idle
        stateHandler.ChangeState(idleState);
    }

    void Update()
    {
        // 示例:按下空格键切换到 Move 状态
        if (Input.GetKeyDown(KeyCode.Space))
        {
            stateHandler.ChangeState(moveState);
        }

        // 示例:按下 ESC 键切换回 Idle 状态
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            stateHandler.ChangeState(idleState);
        }

       // 示例:按下鼠标左键切换回 Attack 状态
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            stateHandler.ChangeState(idleState);
        }
    }
}

看,很简单只要新增东西,不需要修改原本有的东西,而且状态都分开了,不相互粘连,便于维护,就算以后有了新需求三百六十五度阿姆斯特朗回旋喷气式移动,也只需要MoveState状态里修改,看起来很干净,也减少bug出现的可能性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值