65.9K
CodeProject 正在变化。 阅读更多。
Home

动态状态模式

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2023年12月11日

CPOL

1分钟阅读

viewsIcon

5624

在游戏开发中使用此模式的示例

引言

这种模式有助于在切换到另一个状态时,根据该状态是否包含该策略,**激活**和**停用**状态中的**策略**。

本文将描述这种模式在游戏开发中的一个用例示例。

示例场景

玩家有三种状态:角色状态车辆状态过场动画状态。每个状态都有一个按功能分类并放置在相应数组索引(称为**通道**)中的**策略**数组。这些**通道**在状态之间切换时被激活或停用。一些策略将在玩家状态之间共享。

在当前示例中,**策略通道**被定义为 C# Enum(也可以使用整数值)。

public enum StrategyChannel
{
    Camera = 0,
    Input = 1,
    Controls = 2
}

每个**通道策略**可以有任何实现,并且在当前示例中被定义为接口。

public interface IStrategyChannel
{
    StrategyChannel Channel { get; }
    void Activate();
    void Deactivate();
}

CarCameraIStrategyChannel 示例实现

public class CarCamera : IStrategyChannel
{
    public StrategyChannel Channel => StrategyChannel.Camera;

    public void Activate()
    {
        Console.WriteLine("Activate CarCamera");
    }

    public void Deactivate()
    {
        Console.WriteLine("Deactivate CarCamera");
    }
}

在切换到另一个**状态**时,我们跟踪每个**策略通道**中的**策略**变化,并在发生任何变化时**激活**或**停用**相应的**策略**。

状态类实现

public class PlayerState
{
    private const int CHANNELS = 3;
    private readonly IStrategyChannel[] _strategyChannels = new IStrategyChannel[CHANNELS];

    public void SwitchToState(PlayerState state)
    {
        for (var i = 0; i < CHANNELS; i++)
        {
            var currentStrategy = _strategyChannels[i];
            var targetStrategy = state._strategyChannels[i];

            //strategy been changed
            if (currentStrategy != targetStrategy)
            {
                if (currentStrategy != null)
                {
                    currentStrategy.Deactivate();
                }

                if (targetStrategy != null)
                {
                    targetStrategy.Activate();
                }
            }
        }
    }

    public void SetChannelStrategy(IStrategyChannel strategy)
    {
        _strategyChannels[(int)strategy.Channel] = strategy;
    }
}

PlayerStatesController 构建并保存所有状态,跟踪当前状态并初始化初始状态。

public class PlayerStatesController
{
    private PlayerState _currentState;
    public readonly PlayerState CharacterState;
    public readonly PlayerState CarState;
    public readonly PlayerState CinematicState;

    public PlayerStatesController()
    {
        CharacterState = new PlayerState();
        CarState = new PlayerState();
        CinematicState = new PlayerState();

        var playerInput = new PlayerInput();
        CharacterState.SetChannelStrategy(new FreeLookCamera());
        CharacterState.SetChannelStrategy(playerInput);
        CarState.SetChannelStrategy(new CarCamera());
        CarState.SetChannelStrategy(playerInput);
        CarState.SetChannelStrategy(new CarControl());
        CinematicState.SetChannelStrategy(new CinematicCamera());
    }

    public void ActivateInitialState(PlayerState state)
    {
        _currentState = state;
        _currentState.InitialActivate();
    }

    public void SwitchToState(PlayerState state)
    {
        _currentState.SwitchToState(state);
        _currentState = state;
    }
}

使用示例

在此代码示例中,我们按顺序激活每个状态,然后切换回第一个状态。

var statesController = new PlayerStatesController();

Console.WriteLine("Activating initial CharacterState:");
statesController.ActivateInitialState(statesController.CharacterState);
Console.WriteLine();

Console.WriteLine("Switching to CarState:");
statesController.SwitchToState(statesController.CarState);
Console.WriteLine();

Console.WriteLine("Switching to CinematicState:");
statesController.SwitchToState(statesController.CinematicState);
Console.WriteLine();

Console.WriteLine("Switching to CharacterState:");
statesController.SwitchToState(statesController.CharacterState);
Console.WriteLine();

执行后,我们将得到以下输出

Activating initial CharacterState:
Activate FreeLookCamera
Activate PlayerInput

Switching to CarState:
Deactivate FreeLookCamera
Activate CarCamera
Activate CarControl

Switching to CinematicState:
Deactivate CarCamera
Activate CinematicCamera
Deactivate PlayerInput
Deactivate CarControl

Switching to CharacterState:
Deactivate CinematicCamera
Activate FreeLookCamera
Activate PlayerInput

包含示例代码的 Github 仓库: https://github.com/Stridemann/DynamicStrategyStatePattern

历史

  • 2023 年 12 月 12 日:初始版本
© . All rights reserved.