You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决游戏开发中传统State模式的局限性?

解决传统状态模式在游戏开发中的局限性

我在游戏开发中实现了状态模式,比如玩家拥有Idle、Run、Attack等多种状态,每个状态都用独立类实现,且由状态自身负责状态转换逻辑(例如Idle状态可直接转换至Attack状态,而Jump状态需要等玩家落地后才能转换至Idle状态)。以下是最初的实现思路:

class Player
{
    private State _state = null;

    public Player()
    {
        this.TransitionTo(new IdleState(this));
    }

    public void TransitionTo(State state)
    {
        this._state = state;
        this._state.SetPlayer(this);
    }

    public void Jump()
    {
        this._state.jump();
    }
}

abstract class State
{
    protected Player _player;

    public void SetPlayer(Player player)
    {
        this._player = player;
    }

    public abstract void Jump();
}

class JumpState : State
{
    public override void Jump()
    {
        // 不允许二段跳
    }
}

class IdleState : State
{
    public override void Jump()
    {
        this._player.TransitionTo(new JumpState());
    }
}

这个实现能正常运行,但存在两大局限性:

  • 无法灵活替换特定状态实现:比如有的敌人跳跃时可受伤害,有的不可。虽然可以通过override修改Jump状态的行为,但当前实现中状态转换时直接依赖具体状态类(比如IdleState硬编码转换至JumpState),若要换成JumpNoDamageState,就得额外创建对应的IdleNoDamageState,导致类爆炸。
  • 状态与特定角色紧耦合:比如两个敌人基础行为完全一致,仅当生命值低于10%时其中一个会触发Escape状态。按当前实现,必须为这个敌人重新创建所有状态类,因为每个状态都需要知晓新的转换规则和目标状态。

解决方案

核心思路是通过解耦状态与实例创建、解耦状态与具体角色类型来解决这些问题:

1. 将状态实例的创建逻辑从状态类中剥离

让角色(Player/Enemy)负责管理状态实例的创建和存储,状态类只通过角色获取目标状态,而非直接new具体类。这样替换状态实现时,只需要修改角色的状态初始化逻辑,无需改动状态类本身。

示例修改:

// 定义抽象角色接口
public interface ICharacter
{
    void TransitionTo(IState state);
    T GetState<T>() where T : IState;
    bool IsGrounded { get; }
    int Health { get; }
}

// 抽象状态接口
public interface IState
{
    void SetCharacter(ICharacter character);
    void Jump();
    void Update();
}

public abstract class BaseState : IState
{
    protected ICharacter _character;

    public void SetCharacter(ICharacter character)
    {
        _character = character;
    }

    public abstract void Jump();
    public virtual void Update() { }
}

// 修改IdleState,不再硬编码创建JumpState
public class IdleState : BaseState
{
    public override void Jump()
    {
        // 从角色处获取Jump状态实例
        _character.TransitionTo(_character.GetState<JumpState>());
    }
}

// 角色类负责管理状态实例
public class Player : ICharacter
{
    private IState _currentState;
    private readonly Dictionary<Type, IState> _states = new();

    public Player()
    {
        // 初始化状态,可随时替换为不同实现
        _states.Add(typeof(IdleState), new IdleState());
        // 若需要无伤害跳跃,只需替换这里的状态实例
        // _states.Add(typeof(JumpState), new JumpNoDamageState());
        _states.Add(typeof(JumpState), new JumpState());

        TransitionTo(GetState<IdleState>());
    }

    public void TransitionTo(IState state)
    {
        _currentState = state;
        _currentState.SetCharacter(this);
    }

    public T GetState<T>() where T : IState
    {
        return _states[typeof(T)] as T;
    }

    public bool IsGrounded { get; private set; }
    public int Health { get; private set; }

    public void Jump()
    {
        _currentState.Jump();
    }

    public void Update()
    {
        _currentState.Update();
    }
}

2. 让状态依赖抽象角色,分离转换规则与状态逻辑

让状态类依赖抽象的ICharacter接口而非具体的角色类,同时把状态转换的条件判断(比如生命值低于10%转Escape)从状态类中移到角色类或专门的规则类中,让状态类只专注于当前状态的行为逻辑。

示例扩展:

// 新增Escape状态
public class EscapeState : BaseState
{
    public override void Jump()
    {
        // 逃跑状态下的跳跃逻辑
    }

    public override void Update()
    {
        // 逃跑状态的帧更新逻辑
    }
}

// 带逃跑逻辑的敌人
public class EnemyWithEscape : ICharacter
{
    private IState _currentState;
    private readonly Dictionary<Type, IState> _states = new();

    public EnemyWithEscape()
    {
        // 复用通用状态类
        _states.Add(typeof(IdleState), new IdleState());
        _states.Add(typeof(AttackState), new AttackState());
        _states.Add(typeof(JumpState), new JumpState());
        _states.Add(typeof(EscapeState), new EscapeState());

        TransitionTo(GetState<IdleState>());
    }

    // 实现ICharacter接口的其他方法...

    public void Update()
    {
        _currentState.Update();
        // 在角色层处理转换规则,状态类无需知晓
        if (Health < 10 && _currentState is not EscapeState)
        {
            TransitionTo(GetState<EscapeState>());
        }
    }
}

// 普通敌人,无需逃跑状态
public class RegularEnemy : ICharacter
{
    private IState _currentState;
    private readonly Dictionary<Type, IState> _states = new();

    public RegularEnemy()
    {
        // 复用和EnemyWithEscape相同的通用状态类
        _states.Add(typeof(IdleState), new IdleState());
        _states.Add(typeof(AttackState), new AttackState());
        _states.Add(typeof(JumpState), new JumpState());

        TransitionTo(GetState<IdleState>());
    }

    // 实现ICharacter接口的其他方法...

    public void Update()
    {
        _currentState.Update();
        // 无逃跑转换逻辑
    }
}

总结

通过以上两点修改,状态类不再依赖具体的状态实现和角色类型,角色可以灵活替换状态实例、自定义转换规则,避免了类爆炸和紧耦合的问题,让状态模式在游戏开发中更具扩展性。

内容的提问来源于stack exchange,提问作者Victor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 18:07:07