背景与场景
在游戏开发中,实体对象(如角色、敌人、NPC)往往需要同时管理多个维度的状态。以一个典型的游戏敌人为例:
- 行为维度:移动、停止、受击、击退、防御、死亡
- 属性维度:正常、冰冻、燃烧、雷电、中毒
如果用单一状态机描述,需要维护 6 × 5 = 30 个组合状态。当维度增加时,状态数量呈指数级增长。
本文探讨的架构通过正交状态分离策略,将不同维度拆分到独立状态机中,只需维护 6 + 5 = 11 个状态类,通过共享宿主实现协作。
核心架构设计
三层职责划分
css
┌─────────────────────────────────────┐
│ 宿主层 (Host) │
│ - 持有多个状态机实例 │
│ - 提供状态切换入口 │
│ - 管理跨维度协调 │
│ - 处理生命周期 │
└──────────┬──────────────────────────┘
│
┌──────┴──────┐
▼ ▼
┌─────────┐ ┌─────────┐
│ 状态机A │ │ 状态机B │
│ - 状态缓存│ │ - 状态缓存│
│ - 状态分发│ │ - 状态分发│
└────┬────┘ └────┬────┘
│ │
┌──┴──┐ ┌──┴──┐
▼ ▼ ▼ ▼ ▼ ▼
状态类群A 状态类群B
维度协作机制
- 共享参数修正 :属性状态修改
effectSpeed,行为状态读取baseSpeed * effectSpeed - 状态间触发:属性恢复时主动将行为切回默认状态
- 组合条件判断:暂停/恢复时同时读取两个维度的状态值
通用 FSM 框架实现
1. 状态基类
typescript
/**
* 通用状态基类
* @template THost 宿主类型
* @template TStateEnum 状态枚举类型
*/
export abstract class BaseState<THost, TStateEnum> {
public readonly value: TStateEnum;
protected host: THost;
constructor(host: THost, stateValue: TStateEnum) {
this.host = host;
this.value = stateValue;
}
/**
* 状态进入时执行的逻辑
* @param context 上下文信息
*/
abstract execute(context?: any): void | Promise<void>;
/**
* 状态退出时的清理逻辑(可选)
*/
onExit?(): void;
}
2. 通用状态机
kotlin
/**
* 通用状态机
* @template THost 宿主类型
* @template TStateEnum 状态枚举类型
*/
export class StateMachine<THost, TStateEnum> {
private currentState: BaseState<THost, TStateEnum> | null = null;
private stateMap: Map<TStateEnum, BaseState<THost, TStateEnum>> = new Map();
private host: THost;
constructor(host: THost) {
this.host = host;
}
/**
* 注册状态
*/
registerState(state: BaseState<THost, TStateEnum>): void {
this.stateMap.set(state.value, state);
}
/**
* 批量注册状态
*/
registerStates(states: BaseState<THost, TStateEnum>[]): void {
states.forEach(state => this.registerState(state));
}
/**
* 切换状态
*/
switchState(stateValue: TStateEnum, context?: any): void {
const nextState = this.stateMap.get(stateValue);
if (!nextState) {
console.warn(`State ${stateValue} not found`);
return;
}
// 退出当前状态
if (this.currentState?.onExit) {
this.currentState.onExit();
}
// 切换到新状态
this.currentState = nextState;
this.currentState.execute(context);
}
/**
* 获取当前状态值
*/
get value(): TStateEnum | null {
return this.currentState?.value ?? null;
}
/**
* 获取当前状态实例
*/
get current(): BaseState<THost, TStateEnum> | null {
return this.currentState;
}
}
3. 宿主接口
scss
/**
* 状态机宿主接口
*/
export interface IStateMachineHost {
/**
* 初始化状态机
*/
initStateMachines(): void;
/**
* 暂停
*/
pause?(): void;
/**
* 恢复
*/
resume?(): void;
/**
* 销毁
*/
destroy?(): void;
}
使用示例:实现游戏实体状态管理
1. 定义状态枚举
ini
enum ActionState {
MOVE = 'move',
STOP = 'stop',
HIT = 'hit',
DEAD = 'dead',
}
enum AttributeState {
NORMAL = 'normal',
FROZEN = 'frozen',
BURNING = 'burning',
}
2. 实现具体状态类
scala
// 行为状态:移动
class MoveState extends BaseState<EntityController, ActionState> {
constructor(host: EntityController) {
super(host, ActionState.MOVE);
}
execute(): void {
const speed = this.host.baseSpeed * this.host.effectSpeed;
this.host.setVelocity(0, -speed);
}
}
// 行为状态:死亡
class DeadState extends BaseState<EntityController, ActionState> {
constructor(host: EntityController) {
super(host, ActionState.DEAD);
}
execute(): void {
this.host.stopPhysics();
this.host.playDeathEffect();
this.host.scheduleDestroy(0.5);
}
}
// 属性状态:正常
class NormalAttributeState extends BaseState<EntityController, AttributeState> {
constructor(host: EntityController) {
super(host, AttributeState.NORMAL);
}
execute(): void {
this.host.effectSpeed = 1;
this.host.effectDamage = 0;
this.host.resetColor();
}
}
// 属性状态:冰冻
class FrozenAttributeState extends BaseState<EntityController, AttributeState> {
constructor(host: EntityController) {
super(host, AttributeState.FROZEN);
}
execute(): void {
this.host.effectSpeed = 0.5;
this.host.setColor(0, 255, 255);
}
}
3. 实现宿主控制器
kotlin
class EntityController implements IStateMachineHost {
// 基础属性
baseSpeed: number = 1;
baseHealth: number = 100;
// 状态修正属性
effectSpeed: number = 1;
effectDamage: number = 0;
// 状态机实例
private actionStateMachine: StateMachine<EntityController, ActionState>;
private attributeStateMachine: StateMachine<EntityController, AttributeState>;
// 调度器任务 ID
private attributeTimerId: number | null = null;
private dotTimerId: number | null = null;
constructor() {
this.initStateMachines();
}
initStateMachines(): void {
// 初始化行为状态机
this.actionStateMachine = new StateMachine(this);
this.actionStateMachine.registerStates([
new MoveState(this),
new StopState(this),
new HitState(this),
new DeadState(this),
]);
// 初始化属性状态机
this.attributeStateMachine = new StateMachine(this);
this.attributeStateMachine.registerStates([
new NormalAttributeState(this),
new FrozenAttributeState(this),
new BurningAttributeState(this),
]);
// 设置初始状态
this.actionStateMachine.switchState(ActionState.MOVE);
this.attributeStateMachine.switchState(AttributeState.NORMAL);
}
// 行为状态切换入口
switchActionState(state: ActionState, context?: any): void {
const currentState = this.actionStateMachine.value;
// 防重入(MOVE 除外,允许重置)
if (currentState === state && state !== ActionState.MOVE) {
return;
}
this.actionStateMachine.switchState(state, context);
}
// 属性状态切换入口
switchAttributeState(state: AttributeState, context?: any): void {
const currentState = this.attributeStateMachine.value;
// 已经是目标状态,跳过
if (currentState === state) {
return;
}
// 清理旧的调度任务
this.clearAttributeTimers();
// 切换到新状态
this.attributeStateMachine.switchState(state, context);
// 如果不是 NORMAL,设置定时恢复
if (state !== AttributeState.NORMAL) {
this.attributeTimerId = this.scheduleOnce(() => {
this.switchAttributeState(AttributeState.NORMAL);
}, 3.0);
// 如果有持续伤害,设置周期性伤害
if (this.effectDamage > 0) {
this.dotTimerId = this.scheduleRepeat(() => {
this.takeDamage(this.effectDamage);
}, 0.8);
}
}
}
// 清理属性相关定时器
private clearAttributeTimers(): void {
if (this.attributeTimerId !== null) {
this.unschedule(this.attributeTimerId);
this.attributeTimerId = null;
}
if (this.dotTimerId !== null) {
this.unschedule(this.dotTimerId);
this.dotTimerId = null;
}
}
// 获取当前状态
get actionState(): ActionState | null {
return this.actionStateMachine.value;
}
get attributeState(): AttributeState | null {
return this.attributeStateMachine.value;
}
// 暂停
pause(): void {
this.stopPhysics();
// 根据当前状态暂停对应的动画/特效
}
// 恢复
resume(): void {
// 根据当前状态恢复对应的行为
if (this.actionState === ActionState.MOVE) {
const speed = this.baseSpeed * this.effectSpeed;
this.setVelocity(0, -speed);
}
}
// 销毁
destroy(): void {
this.clearAttributeTimers();
// 其他清理逻辑
}
// 以下是宿主提供给状态类使用的方法
setVelocity(x: number, y: number): void { /* ... */ }
stopPhysics(): void { /* ... */ }
playDeathEffect(): void { /* ... */ }
setColor(r: number, g: number, b: number): void { /* ... */ }
resetColor(): void { /* ... */ }
takeDamage(damage: number): void { /* ... */ }
scheduleOnce(callback: () => void, delay: number): number { /* ... */ return 0; }
scheduleRepeat(callback: () => void, interval: number): number { /* ... */ return 0; }
unschedule(timerId: number): void { /* ... */ }
scheduleDestroy(delay: number): void { /* ... */ }
}
状态生命周期模式
瞬时状态
依赖外部事件自动回切,适合表现类状态:
scala
class HitState extends BaseState<EntityController, ActionState> {
execute(): void {
this.host.playHitEffect();
// 监听动画结束事件
this.host.onEffectFinished(() => {
this.host.switchActionState(ActionState.MOVE);
});
}
}
持续状态
由宿主管理生命周期,适合带持续效果的状态:
kotlin
// 在宿主的 switchAttributeState 中统一管理
switchAttributeState(state: AttributeState): void {
// 清理旧状态任务
this.clearAttributeTimers();
// 切换状态
this.attributeStateMachine.switchState(state);
// 注册新状态的定时任务
if (state !== AttributeState.NORMAL) {
this.scheduleOnce(() => {
this.switchAttributeState(AttributeState.NORMAL);
}, 3.0);
}
}
终止状态
集中处理资源回收:
scala
class DeadState extends BaseState<EntityController, ActionState> {
execute(): void {
// 停止物理
this.host.stopPhysics();
// 播放特效
this.host.playDeathEffect();
// 发放奖励
this.host.grantRewards();
// 记录统计
this.host.recordKill();
// 清理调度任务
this.host.clearAllTimers();
// 延迟回收
this.host.scheduleDestroy(0.5);
}
}
架构优势
状态空间可控
- 单一状态机:N × M 个状态类
- 多维度状态机:N + M 个状态类
职责清晰
- 状态机:状态查找与分发,不关心业务逻辑
- 状态类:具体行为执行,持有宿主引用
- 宿主:协调多个状态机,管理生命周期
扩展性强
新增维度只需:
- 创建新的状态机实例
- 实现该维度的状态类
- 在宿主中添加切换入口
已有维度无需修改。
设计权衡
状态类与宿主的耦合度
当前方案:状态类直接持有宿主引用,可以访问宿主的所有方法和属性。
优点:开发效率高,状态实现直观
缺点:耦合度高,状态类依赖宿主的具体实现
替代方案:定义状态操作接口,状态类只能通过接口操作宿主。
scala
interface IStateOperations {
setVelocity(x: number, y: number): void;
playEffect(effectName: string): void;
// ...
}
class MoveState extends BaseState<IStateOperations, ActionState> {
execute(): void {
// 只能通过接口操作
this.host.setVelocity(0, -1);
}
}
生命周期管理位置
当前方案:持续状态的生命周期由宿主统一管理。
优点:调度任务集中管理,便于清理
缺点:状态逻辑被拆分到状态类和宿主两处
替代方案:状态类自己管理生命周期。
scala
class BurningState extends BaseState<EntityController, AttributeState> {
private timerId: number | null = null;
execute(): void {
this.host.setColor(255, 0, 0);
// 状态自己注册定时器
this.timerId = this.host.scheduleOnce(() => {
this.host.switchAttributeState(AttributeState.NORMAL);
}, 3.0);
}
onExit(): void {
// 状态退出时清理
if (this.timerId !== null) {
this.host.unschedule(this.timerId);
}
}
}
适用场景
适合使用:
- 实体状态由多个正交维度组成
- 状态切换频繁,需要高性能
- 状态行为与表现资源紧密绑定
- 需要清晰的生命周期管理
不适合使用:
- 状态维度单一且简单(直接用枚举 + switch 即可)
- 状态转换有复杂的条件依赖(需要状态转换图)
- 状态之间有严格的顺序约束
项目应用实例
场景描述
在一个塔防类游戏项目中,敌人系统需要同时管理:
行为维度(7 个状态):
- MOVE:向下移动
- STOP:停止
- HIT:普通受击
- CRITICAL_HIT:暴击受击
- REPULSE:击退
- DEFENSE:防御
- DEAD:死亡
属性维度(5 个状态):
- NORMAL:正常
- FROZEN:冰冻(减速 + 视觉效果)
- FIRE:燃烧(持续伤害 + 视觉效果)
- THUNDER:雷电(定身 + 视觉效果)
- POISON:中毒(持续伤害 + 视觉效果)
如果用单一状态机,需要维护 7 × 5 = 35 个组合状态。采用双状态机架构后,只需维护 7 + 5 = 12 个状态类。
核心实现
1. 行为状态机实现
kotlin
// EnemyActionStateMachine.ts
export class EnemyActionStateMachine {
private _state: BaseState;
private _stateMap: Map<ENEMY_ACTION_STATE, BaseState> = new Map();
constructor(node: Node, EnemyController: any, initialState: ENEMY_ACTION_STATE) {
// 预创建所有状态实例
this._initState(node, EnemyController, ENEMY_ACTION_STATE.MOVE);
this._initState(node, EnemyController, ENEMY_ACTION_STATE.STOP);
this._initState(node, EnemyController, ENEMY_ACTION_STATE.HIT);
this._initState(node, EnemyController, ENEMY_ACTION_STATE.CRITICAL_HIT);
this._initState(node, EnemyController, ENEMY_ACTION_STATE.REPULSE);
this._initState(node, EnemyController, ENEMY_ACTION_STATE.DEFENSE);
this._initState(node, EnemyController, ENEMY_ACTION_STATE.DEAD);
this.switchState(initialState);
}
private async _initState(node: Node, Controller: any, state: ENEMY_ACTION_STATE) {
let stateInstance: BaseState;
switch (state) {
case ENEMY_ACTION_STATE.MOVE:
stateInstance = new MoveState(node, Controller);
break;
case ENEMY_ACTION_STATE.DEAD:
stateInstance = new DeadState(node, Controller);
break;
// ... 其他状态
}
this._stateMap.set(state, stateInstance);
}
switchState(actionState: ENEMY_ACTION_STATE, info?: any) {
let state = this._stateMap.get(actionState);
if (!state) state = this._stateMap.get(ENEMY_ACTION_STATE.MOVE);
this._state = state;
return this._state.action(info);
}
get value(): ENEMY_ACTION_STATE {
return this._state?.value;
}
}
2. 关键状态类实现
移动状态:读取属性状态的速度修正
scala
// MoveState.ts
export default class MoveState extends BaseState {
async action(info: any) {
// 速度 = 基础速度 × 属性效果修正
const finalSpeed = this.EnemyController.baseSpeed
* this.EnemyController.effectSpeed;
this.EnemyController.RigidBodyBox.linearVelocity = new Vec2(0, -finalSpeed);
}
}
死亡状态:作为生命周期终点,集中处理清理逻辑
kotlin
// DeadState.ts
export default class DeadState extends BaseState {
async action(info: any) {
// 1. 停止物理和动画
this.EnemyController.Animation.pause();
this.EnemyController.RigidBodyBox.enabled = false;
this.EnemyController.RigidBodyBox.linearVelocity = new Vec2(0, 0);
// 2. 播放死亡特效
this.EnemyController.ExplosionEffect.active = true;
this.EnemyController.ExplosionEffect.getComponent(Animation).play();
// 3. 发放经验和记录统计
PlayerDataManager.instance.setExp(this.EnemyController.baseExp);
PlayDataManager.instance.killEnemiesMap.set(
this.EnemyController.index,
(PlayDataManager.instance.killEnemiesMap.get(this.EnemyController.index) || 0) + 1
);
// 4. 清空所有调度任务
director.getScheduler().unscheduleAllForTarget(this.EnemyController);
// 5. 延迟回收到对象池
this.EnemyController.scheduleOnce(() => {
this.EnemyNode.active = false;
// 重置所有属性
this.EnemyController.baseHp = this.EnemyController.originHp;
this.EnemyController.effectSpeed = 1;
this.EnemyController.effectDamage = 0;
// 解绑事件
this.EnemyController.ColliderBox.off(Contact2DType.BEGIN_CONTACT);
this.EnemyController.ColliderBox.off(Contact2DType.END_CONTACT);
// 放回对象池
NodePoolManager.instance.putNodeToPool(
`Enemy-${this.EnemyController.category}-${this.EnemyController.index}`,
this.EnemyNode
);
}, 0.65);
}
}
受击状态:瞬时状态,依赖动画事件自动回切
scala
// HitState.ts
export default class HitState extends BaseState {
async action(info: any) {
// 激活受击特效
this.EnemyController.HitEffect.active = true;
this.EnemyController.HitEffect.getComponent(Animation).play();
// 监听动画结束事件,自动切回移动状态
this.EnemyController.HitEffect.getComponent(Animation).on(
AnimationComponent.EventType.FINISHED,
() => {
this.EnemyController.HitEffect.active = false;
this.EnemyController.switchActionState(ENEMY_ACTION_STATE.MOVE);
}
);
}
}
3. 属性状态实现
正常状态:作为属性维度的重置模板
scala
// NormalState.ts
export default class NormalState extends BaseState {
async attribute(info: any) {
// 重置所有属性修正
this.EnemyController.effectSpeed = 1;
this.EnemyController.effectDamage = 0;
// 恢复默认视觉
this.EnemyController.Sprite.color = new Color(255, 255, 255, 255);
this.EnemyController.Animation.resume();
// 恢复移动
this.EnemyController.RigidBodyBox.linearVelocity = new Vec2(
0,
-1 * this.EnemyController.baseSpeed * this.EnemyController.effectSpeed
);
// 主动将行为状态拉回移动
this.EnemyController.switchActionState(ENEMY_ACTION_STATE.MOVE);
}
}
冰冻状态:修改速度修正参数
scala
// FrozenState.ts
export default class FrozenState extends BaseState {
async attribute(info: any) {
// 修改视觉效果
this.EnemyController.Sprite.color = new Color(255, 255, 0, 255);
// 修改速度修正(不直接改速度,而是改修正系数)
// 行为状态的 MoveState 会读取这个值
this.EnemyController.effectSpeed = 0.5;
}
}
燃烧状态:带持续伤害
scala
// FireState.ts
export default class FireState extends BaseState {
async attribute(info: any) {
this.EnemyController.Sprite.color = new Color(65, 255, 65);
// 设置持续伤害参数
// 宿主会根据这个值注册周期性伤害回调
this.EnemyController.effectDamage = info?.damage || 2;
}
}
4. 宿主控制器实现
kotlin
// EnemyController.ts
export class EnemyController extends Component {
// 基础属性
baseHp: number = 18;
baseSpeed: number = 1.15;
baseAttack: number = 4;
// 状态修正属性(供状态类修改)
effectSpeed: number = 1;
effectDamage: number = 0;
// 状态机实例
enemyActionState: EnemyActionStateMachine;
enemyAttributeState: EnemyAttributeStateMachine;
initStateMachine() {
this.enemyActionState = new EnemyActionStateMachine(
this.node,
EnemyController,
ENEMY_ACTION_STATE.MOVE
);
this.enemyAttributeState = new EnemyAttributeStateMachine(
this.node,
EnemyController,
ENEMY_ATTRIBUTE_STATE.NORMAL
);
}
// 行为状态切换入口
switchActionState(actionState: ENEMY_ACTION_STATE, info?: any) {
// 防重入,但 MOVE 允许重复进入(用于重置)
if ((this.actionState !== actionState) || (actionState === ENEMY_ACTION_STATE.MOVE)) {
return this.enemyActionState.switchState(actionState, info);
}
}
// 属性状态切换入口(带生命周期管理)
switchAttributeState(attrState: ENEMY_ATTRIBUTE_STATE, info?: any) {
// 某些行为状态下禁止切换属性
if ([ENEMY_ACTION_STATE.STOP].includes(this.actionState)) return;
if (this.attributeState === attrState) return;
// 清理旧属性的调度任务
this.unschedule(this.enemyAttributeState.switchState);
this.unschedule(this.runAttributeHit);
// 立即切换到新属性
this.runSwitchAttributeState(attrState, info);
// 3.2 秒后自动恢复到 NORMAL
this.scheduleOnce(this.runSwitchAttributeState, 3.2);
// 如果有持续伤害,注册周期性伤害回调
if (this.effectDamage) {
this.schedule(this.runAttributeHit, 0.88);
}
}
runSwitchAttributeState(attrState: ENEMY_ATTRIBUTE_STATE = ENEMY_ATTRIBUTE_STATE.NORMAL, info?: any) {
return this.enemyAttributeState.switchState(attrState, info);
}
runAttributeHit() {
if (this.effectDamage) {
handleHurtEvent(this, this.effectDamage);
}
}
// 暂停/恢复时需要同时考虑两个维度的状态
setResume() {
director.getScheduler().resumeTarget(this);
// 恢复移动速度(读取属性修正)
this.RigidBodyBox.linearVelocity = new Vec2(
0,
-1 * this.baseSpeed * this.effectSpeed
);
// 根据属性状态决定是否恢复主动画
if (this.attributeState !== ENEMY_ATTRIBUTE_STATE.THUNDER) {
this.Animation.resume();
}
// 根据行为状态恢复对应特效
if (this.actionState === ENEMY_ACTION_STATE.HIT) {
this.HitEffect.getComponent(Animation).resume();
}
if (this.actionState === ENEMY_ACTION_STATE.DEAD) {
this.ExplosionEffect.getComponent(Animation).resume();
}
}
get actionState(): ENEMY_ACTION_STATE {
return this.enemyActionState?.value || ENEMY_ACTION_STATE.MOVE;
}
get attributeState(): ENEMY_ATTRIBUTE_STATE {
return this.enemyAttributeState?.value || ENEMY_ATTRIBUTE_STATE.NORMAL;
}
}
实际运行效果
场景 1:敌人被冰冻后受击
scss
// 1. 敌人初始状态
enemy.actionState === ENEMY_ACTION_STATE.MOVE
enemy.attributeState === ENEMY_ATTRIBUTE_STATE.NORMAL
enemy.effectSpeed === 1 // 正常速度
// 2. 玩家使用冰冻技能
enemy.switchAttributeState(ENEMY_ATTRIBUTE_STATE.FROZEN);
// → FrozenState.attribute() 执行
// → enemy.effectSpeed = 0.5
// → 颜色变为黄色
// → 3.2 秒后自动恢复 NORMAL
// 3. 此时敌人仍在移动,但速度变慢
// MoveState 读取 baseSpeed * effectSpeed = 1.15 * 0.5 = 0.575
// 4. 敌人被攻击
enemy.switchAttributeState(ENEMY_ACTION_STATE.HIT);
// → HitState.action() 执行
// → 播放受击特效
// → 动画结束后自动切回 MOVE
// 5. 冰冻效果持续,移动速度仍然是减速状态
场景 2:敌人中毒后死亡
scss
// 1. 敌人中毒
enemy.switchAttributeState(ENEMY_ATTRIBUTE_STATE.POISON, { damage: 3 });
// → PoisonState.attribute() 执行
// → enemy.effectDamage = 3
// → 颜色变为紫色
// → 宿主注册周期性伤害回调(每 0.88 秒触发一次)
// 2. 持续伤害触发
// 每 0.88 秒执行一次 runAttributeHit()
// → handleHurtEvent(enemy, 3)
// → enemy.baseHp -= 3
// 3. 血量归零
if (enemy.baseHp <= 0) {
enemy.switchActionState(ENEMY_ACTION_STATE.DEAD);
// → DeadState.action() 执行
// → 停止物理和动画
// → 播放爆炸特效
// → 发放经验
// → 记录击杀统计
// → 清空所有调度任务(包括中毒的持续伤害)
// → 0.65 秒后回收到对象池
}
场景 3:游戏暂停/恢复
scss
// 暂停时
gameManager.pauseGame();
// → 遍历所有敌人
// → 调用 enemy.setPause()
// → 停止物理、动画、特效
// 恢复时
gameManager.resumeGame();
// → 遍历所有敌人
// → 调用 enemy.setResume()
// → 根据 actionState 和 attributeState 的组合决定恢复行为
// 示例:敌人处于"移动 + 冰冻"状态
if (enemy.actionState === ENEMY_ACTION_STATE.MOVE) {
// 恢复移动,速度 = baseSpeed * effectSpeed(冰冻修正)
enemy.setVelocity(0, -1.15 * 0.5);
}
if (enemy.attributeState !== ENEMY_ATTRIBUTE_STATE.THUNDER) {
// 非雷电状态才恢复主动画
enemy.Animation.resume();
}
架构收益
通过这套双状态机架构,项目获得了:
- 状态数量可控:12 个状态类 vs 35 个组合状态
- 代码复用:4 种敌人类型(Tiny、Sub、Boss、Special)共享同一套状态机逻辑
- 易于扩展:新增属性效果(如"眩晕")只需添加一个属性状态类
- 清晰的生命周期:死亡状态集中处理所有清理逻辑,不会遗漏
- 表现驱动:受击、暴击等状态依赖动画事件自动回切,无需轮询
总结
多维度状态机架构通过正交分离策略,将复杂状态空间拆解为多个独立维度。核心价值在于:
- 控制状态爆炸:N + M 而非 N × M
- 职责清晰:状态机、状态类、宿主各司其职
- 易于扩展:新增维度不影响已有维度
- 表现驱动:状态切换由事件驱动,而非轮询判断
实现时需要权衡:
- 状态类与宿主的耦合度
- 生命周期管理的位置
- 状态机数量与协调复杂度
通用框架提供了基础的状态机、状态基类和宿主接口,可以根据具体场景灵活扩展。