动态状态模式





5.00/5 (2投票s)
在游戏开发中使用此模式的示例
引言
这种模式有助于在切换到另一个状态时,根据该状态是否包含该策略,**激活**和**停用**状态中的**策略**。
本文将描述这种模式在游戏开发中的一个用例示例。
示例场景
玩家有三种状态:角色状态、车辆状态和过场动画状态。每个状态都有一个按功能分类并放置在相应数组索引(称为**通道**)中的**策略**数组。这些**通道**在状态之间切换时被激活或停用。一些策略将在玩家状态之间共享。
在当前示例中,**策略通道**被定义为 C# Enum
(也可以使用整数值)。
public enum StrategyChannel
{
Camera = 0,
Input = 1,
Controls = 2
}
每个**通道策略**可以有任何实现,并且在当前示例中被定义为接口。
public interface IStrategyChannel
{
StrategyChannel Channel { get; }
void Activate();
void Deactivate();
}
CarCamera
的 IStrategyChannel
示例实现
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 日:初始版本