FSM状态机
This commit is contained in:
9
client/assets/scripts/Framework.meta
Normal file
9
client/assets/scripts/Framework.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "6426d655-54cb-4449-b6e8-1ab2f7707997",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
9
client/assets/scripts/Framework/FSM.meta
Normal file
9
client/assets/scripts/Framework/FSM.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "a669701c-71dc-4aa3-9ffe-b9f4a8a884ac",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
53
client/assets/scripts/Framework/FSM/BaseState.ts
Normal file
53
client/assets/scripts/Framework/FSM/BaseState.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { IState } from "./IState";
|
||||
|
||||
/**
|
||||
* 状态基类
|
||||
* 提供状态接口的基础实现
|
||||
*/
|
||||
export abstract class BaseState implements IState {
|
||||
/**
|
||||
* 状态所属的状态机
|
||||
*/
|
||||
protected _fsm: any;
|
||||
|
||||
/**
|
||||
* 状态名称
|
||||
*/
|
||||
public readonly name: string;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param fsm 状态所属的状态机
|
||||
* @param name 状态名称
|
||||
*/
|
||||
constructor(fsm: any, name: string) {
|
||||
this._fsm = fsm;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 进入状态
|
||||
* 子类可以重写此方法来实现自定义逻辑
|
||||
* @param params 可选参数
|
||||
*/
|
||||
onEnter(params?: any): void {
|
||||
console.log(`[FSM] 进入状态: ${this.name}`, params || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新状态
|
||||
* 子类可以重写此方法来实现每帧更新逻辑
|
||||
* @param dt 距离上一帧的时间增量(秒)
|
||||
*/
|
||||
onUpdate?(dt: number): void {
|
||||
// 子类可选择实现
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出状态
|
||||
* 子类可以重写此方法来实现清理逻辑
|
||||
*/
|
||||
onExit(): void {
|
||||
console.log(`[FSM] 退出状态: ${this.name}`);
|
||||
}
|
||||
}
|
||||
9
client/assets/scripts/Framework/FSM/BaseState.ts.meta
Normal file
9
client/assets/scripts/Framework/FSM/BaseState.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e27b7261-06e4-49d9-9936-bbf7aa6abacf",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
139
client/assets/scripts/Framework/FSM/FSM.ts
Normal file
139
client/assets/scripts/Framework/FSM/FSM.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { IState } from "./IState";
|
||||
|
||||
/**
|
||||
* 有限状态机 (Finite State Machine)
|
||||
* 管理状态的添加、移除和切换
|
||||
*/
|
||||
export class FSM {
|
||||
/**
|
||||
* 存储所有状态的Map,键为状态名称
|
||||
*/
|
||||
private _states: Map<string, IState>;
|
||||
|
||||
/**
|
||||
* 当前活动的状态
|
||||
*/
|
||||
private _currentState: IState | null;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
constructor() {
|
||||
this._states = new Map<string, IState>();
|
||||
this._currentState = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加状态
|
||||
* @param state 要添加的状态
|
||||
*/
|
||||
addState(state: IState): void {
|
||||
if (this._states.has(state.name)) {
|
||||
console.warn(`[FSM] 状态 "${state.name}" 已存在,将被覆盖`);
|
||||
}
|
||||
this._states.set(state.name, state);
|
||||
console.log(`[FSM] 添加状态: ${state.name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除状态
|
||||
* @param stateName 要移除的状态名称
|
||||
*/
|
||||
removeState(stateName: string): void {
|
||||
if (!this._states.has(stateName)) {
|
||||
console.warn(`[FSM] 状态 "${stateName}" 不存在,无法移除`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果当前状态就是要移除的状态,先退出
|
||||
if (this._currentState && this._currentState.name === stateName) {
|
||||
this._currentState.onExit();
|
||||
this._currentState = null;
|
||||
}
|
||||
|
||||
this._states.delete(stateName);
|
||||
console.log(`[FSM] 移除状态: ${stateName}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换状态
|
||||
* @param stateName 要切换到的状态名称
|
||||
* @param params 可选参数,传递给新状态的onEnter方法
|
||||
*/
|
||||
changeState(stateName: string, params?: any): void {
|
||||
const newState = this._states.get(stateName);
|
||||
|
||||
if (!newState) {
|
||||
console.error(`[FSM] 状态 "${stateName}" 不存在,无法切换`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 退出当前状态
|
||||
if (this._currentState) {
|
||||
this._currentState.onExit();
|
||||
}
|
||||
|
||||
// 切换到新状态
|
||||
this._currentState = newState;
|
||||
this._currentState.onEnter(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前状态
|
||||
* @returns 当前活动的状态,如果没有状态则返回null
|
||||
*/
|
||||
getCurrentState(): IState | null {
|
||||
return this._currentState;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前状态名称
|
||||
* @returns 当前状态名称,如果没有状态则返回null
|
||||
*/
|
||||
getCurrentStateName(): string | null {
|
||||
return this._currentState ? this._currentState.name : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否存在指定状态
|
||||
* @param stateName 状态名称
|
||||
* @returns 如果状态存在返回true,否则返回false
|
||||
*/
|
||||
hasState(stateName: string): boolean {
|
||||
return this._states.has(stateName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取状态
|
||||
* @param stateName 状态名称
|
||||
* @returns 状态实例,如果不存在则返回undefined
|
||||
*/
|
||||
getState(stateName: string): IState | undefined {
|
||||
return this._states.get(stateName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新状态机
|
||||
* 如果当前状态实现了onUpdate方法,则调用它
|
||||
* @param dt 距离上一帧的时间增量(秒)
|
||||
*/
|
||||
update(dt: number): void {
|
||||
if (this._currentState && this._currentState.onUpdate) {
|
||||
this._currentState.onUpdate(dt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有状态
|
||||
*/
|
||||
clear(): void {
|
||||
// 退出当前状态
|
||||
if (this._currentState) {
|
||||
this._currentState.onExit();
|
||||
this._currentState = null;
|
||||
}
|
||||
|
||||
this._states.clear();
|
||||
console.log('[FSM] 已清空所有状态');
|
||||
}
|
||||
}
|
||||
9
client/assets/scripts/Framework/FSM/FSM.ts.meta
Normal file
9
client/assets/scripts/Framework/FSM/FSM.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "775f2d87-91ed-4af7-bec6-d03bbf83a3eb",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
194
client/assets/scripts/Framework/FSM/FSMExample.ts
Normal file
194
client/assets/scripts/Framework/FSM/FSMExample.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
import { FSM } from "./FSM";
|
||||
import { BaseState } from "./BaseState";
|
||||
|
||||
/**
|
||||
* FSM 使用示例
|
||||
* 展示如何创建和使用状态机
|
||||
*/
|
||||
|
||||
// ========== 示例1: 角色状态机 ==========
|
||||
|
||||
/**
|
||||
* 待机状态
|
||||
*/
|
||||
class IdleState extends BaseState {
|
||||
constructor(fsm: FSM) {
|
||||
super(fsm, "Idle");
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
console.log("角色进入待机状态");
|
||||
}
|
||||
|
||||
onExit(): void {
|
||||
super.onExit();
|
||||
console.log("角色离开待机状态");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动状态
|
||||
*/
|
||||
class MoveState extends BaseState {
|
||||
private speed: number = 1;
|
||||
|
||||
constructor(fsm: FSM) {
|
||||
super(fsm, "Move");
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
if (params && params.speed) {
|
||||
this.speed = params.speed;
|
||||
}
|
||||
console.log(`角色开始移动,速度: ${this.speed}`);
|
||||
}
|
||||
|
||||
onUpdate(dt: number): void {
|
||||
console.log(`移动中... 速度: ${this.speed}`);
|
||||
// 在这里实现移动逻辑
|
||||
}
|
||||
|
||||
onExit(): void {
|
||||
super.onExit();
|
||||
console.log("角色停止移动");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 攻击状态
|
||||
*/
|
||||
class AttackState extends BaseState {
|
||||
constructor(fsm: FSM) {
|
||||
super(fsm, "Attack");
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
console.log("角色进入攻击状态");
|
||||
// 播放攻击动画
|
||||
// 延迟后自动返回待机状态
|
||||
setTimeout(() => {
|
||||
if (this._fsm.getCurrentStateName() === this.name) {
|
||||
this._fsm.changeState("Idle");
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 死亡状态
|
||||
*/
|
||||
class DeadState extends BaseState {
|
||||
constructor(fsm: FSM) {
|
||||
super(fsm, "Dead");
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
console.log("角色死亡");
|
||||
// 播放死亡动画
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 使用示例 ==========
|
||||
|
||||
/**
|
||||
* 创建角色状态机
|
||||
*/
|
||||
export function createCharacterFSM(): FSM {
|
||||
const fsm = new FSM();
|
||||
|
||||
// 添加所有状态
|
||||
fsm.addState(new IdleState(fsm));
|
||||
fsm.addState(new MoveState(fsm));
|
||||
fsm.addState(new AttackState(fsm));
|
||||
fsm.addState(new DeadState(fsm));
|
||||
|
||||
// 设置初始状态
|
||||
fsm.changeState("Idle");
|
||||
|
||||
return fsm;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试状态机
|
||||
*/
|
||||
export function testFSM(): void {
|
||||
console.log("========== 开始测试FSM ==========");
|
||||
|
||||
const fsm = createCharacterFSM();
|
||||
|
||||
// 测试状态切换
|
||||
console.log("\n--- 测试1: 从待机到移动 ---");
|
||||
fsm.changeState("Move", { speed: 5 });
|
||||
|
||||
console.log("\n--- 测试2: 从移动到攻击 ---");
|
||||
fsm.changeState("Attack");
|
||||
|
||||
// 等待攻击状态自动结束
|
||||
setTimeout(() => {
|
||||
console.log("\n--- 测试3: 攻击结束后返回待机 ---");
|
||||
console.log(`当前状态: ${fsm.getCurrentStateName()}`);
|
||||
|
||||
console.log("\n--- 测试4: 角色死亡 ---");
|
||||
fsm.changeState("Dead");
|
||||
|
||||
console.log("\n========== FSM测试完成 ==========");
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
// ========== 示例2: 简单的游戏状态机 ==========
|
||||
|
||||
class MenuState extends BaseState {
|
||||
constructor(fsm: FSM) {
|
||||
super(fsm, "Menu");
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
console.log("显示主菜单");
|
||||
}
|
||||
}
|
||||
|
||||
class PlayingState extends BaseState {
|
||||
constructor(fsm: FSM) {
|
||||
super(fsm, "Playing");
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
console.log("游戏开始");
|
||||
}
|
||||
|
||||
onUpdate(dt: number): void {
|
||||
// 游戏主循环
|
||||
}
|
||||
}
|
||||
|
||||
class PausedState extends BaseState {
|
||||
constructor(fsm: FSM) {
|
||||
super(fsm, "Paused");
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
console.log("游戏暂停");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建游戏状态机
|
||||
*/
|
||||
export function createGameFSM(): FSM {
|
||||
const fsm = new FSM();
|
||||
|
||||
fsm.addState(new MenuState(fsm));
|
||||
fsm.addState(new PlayingState(fsm));
|
||||
fsm.addState(new PausedState(fsm));
|
||||
|
||||
fsm.changeState("Menu");
|
||||
|
||||
return fsm;
|
||||
}
|
||||
9
client/assets/scripts/Framework/FSM/FSMExample.ts.meta
Normal file
9
client/assets/scripts/Framework/FSM/FSMExample.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "d4b05ea7-41dd-4f10-a5df-da10f91aa330",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
30
client/assets/scripts/Framework/FSM/IState.ts
Normal file
30
client/assets/scripts/Framework/FSM/IState.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 状态接口
|
||||
* 定义状态机中状态的标准接口
|
||||
*/
|
||||
export interface IState {
|
||||
/**
|
||||
* 状态名称
|
||||
* 用于标识和切换状态
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* 进入状态时调用
|
||||
* @param params 可选参数,用于传递状态切换时的数据
|
||||
*/
|
||||
onEnter(params?: any): void;
|
||||
|
||||
/**
|
||||
* 更新状态(可选)
|
||||
* 如果状态需要每帧更新,可以实现此方法
|
||||
* @param dt 距离上一帧的时间增量(秒)
|
||||
*/
|
||||
onUpdate?(dt: number): void;
|
||||
|
||||
/**
|
||||
* 退出状态时调用
|
||||
* 用于清理状态相关的资源
|
||||
*/
|
||||
onExit(): void;
|
||||
}
|
||||
9
client/assets/scripts/Framework/FSM/IState.ts.meta
Normal file
9
client/assets/scripts/Framework/FSM/IState.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "e1f22ce5-2a7d-440c-8532-cece7a66a2bc",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
396
client/assets/scripts/Framework/FSM/README.md
Normal file
396
client/assets/scripts/Framework/FSM/README.md
Normal file
@@ -0,0 +1,396 @@
|
||||
# 状态机模块 (Framework/FSM)
|
||||
|
||||
## 📋 模块概述
|
||||
通用的有限状态机(FSM)框架,支持状态切换、状态生命周期管理,可用于游戏状态、AI行为、动画控制等场景。
|
||||
|
||||
## 🎯 核心特性
|
||||
- ✅ 标准状态接口定义
|
||||
- ✅ 状态基类实现
|
||||
- ✅ 状态机核心管理
|
||||
- ✅ 完整的生命周期
|
||||
- ✅ 状态切换管理
|
||||
- ✅ 状态更新机制
|
||||
|
||||
## 🗂️ 文件结构
|
||||
|
||||
```
|
||||
Framework/FSM/
|
||||
├── IState.ts # 状态接口
|
||||
├── BaseState.ts # 状态基类
|
||||
└── FSM.ts # 状态机核心
|
||||
```
|
||||
|
||||
## 📘 核心类详解
|
||||
|
||||
### IState - 状态接口
|
||||
|
||||
**职责**: 定义状态机中状态的标准接口
|
||||
|
||||
```typescript
|
||||
interface IState {
|
||||
// 状态名称(只读)
|
||||
readonly name: string;
|
||||
|
||||
// 进入状态时调用
|
||||
onEnter(params?: any): void;
|
||||
|
||||
// 更新状态(可选,每帧调用)
|
||||
onUpdate?(dt: number): void;
|
||||
|
||||
// 退出状态时调用
|
||||
onExit(): void;
|
||||
}
|
||||
```
|
||||
|
||||
### BaseState - 状态基类
|
||||
|
||||
**职责**: 提供状态接口的基础实现
|
||||
|
||||
```typescript
|
||||
abstract class BaseState implements IState {
|
||||
protected _fsm: FSM; // 状态所属的状态机
|
||||
readonly name: string; // 状态名称
|
||||
|
||||
constructor(fsm: FSM, name: string);
|
||||
|
||||
// 进入状态(可重写)
|
||||
onEnter(params?: any): void {
|
||||
console.log(`[FSM] Enter state: ${this.name}`);
|
||||
}
|
||||
|
||||
// 更新状态(可重写)
|
||||
onUpdate?(dt: number): void {}
|
||||
|
||||
// 退出状态(可重写)
|
||||
onExit(): void {
|
||||
console.log(`[FSM] Exit state: ${this.name}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### FSM - 状态机核心
|
||||
|
||||
**职责**: 管理状态的添加、移除和切换
|
||||
|
||||
```typescript
|
||||
class FSM {
|
||||
private _states: Map<string, IState>; // 状态集合
|
||||
private _currentState: IState | null; // 当前状态
|
||||
|
||||
// 添加状态
|
||||
addState(state: IState): void;
|
||||
|
||||
// 移除状态
|
||||
removeState(stateName: string): void;
|
||||
|
||||
// 切换状态
|
||||
changeState(stateName: string, params?: any): void;
|
||||
|
||||
// 获取当前状态
|
||||
getCurrentState(): IState | null;
|
||||
|
||||
// 获取当前状态名称
|
||||
getCurrentStateName(): string | null;
|
||||
|
||||
// 检查状态是否存在
|
||||
hasState(stateName: string): boolean;
|
||||
|
||||
// 获取状态实例
|
||||
getState(stateName: string): IState | undefined;
|
||||
|
||||
// 更新状态机(调用当前状态的 onUpdate)
|
||||
update(dt: number): void;
|
||||
|
||||
// 清空所有状态
|
||||
clear(): void;
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 使用指南
|
||||
|
||||
### 1. 定义状态类
|
||||
|
||||
```typescript
|
||||
import { FSM } from './Framework/FSM/FSM';
|
||||
import { BaseState } from './Framework/FSM/BaseState';
|
||||
|
||||
// 待机状态
|
||||
class IdleState extends BaseState {
|
||||
constructor(fsm: FSM) {
|
||||
super(fsm, "Idle");
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
console.log("角色进入待机状态");
|
||||
}
|
||||
|
||||
onUpdate(dt: number): void {
|
||||
// 检测输入,切换到移动状态
|
||||
if (hasInput()) {
|
||||
this._fsm.changeState("Move");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移动状态
|
||||
class MoveState extends BaseState {
|
||||
private _speed: number = 5;
|
||||
|
||||
constructor(fsm: FSM) {
|
||||
super(fsm, "Move");
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
if (params?.speed) {
|
||||
this._speed = params.speed;
|
||||
}
|
||||
console.log(`角色开始移动,速度: ${this._speed}`);
|
||||
}
|
||||
|
||||
onUpdate(dt: number): void {
|
||||
// 执行移动逻辑
|
||||
this.move(dt);
|
||||
|
||||
// 检测停止输入
|
||||
if (!hasInput()) {
|
||||
this._fsm.changeState("Idle");
|
||||
}
|
||||
}
|
||||
|
||||
onExit(): void {
|
||||
super.onExit();
|
||||
console.log("角色停止移动");
|
||||
}
|
||||
|
||||
private move(dt: number): void {
|
||||
// 移动逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 创建并使用状态机
|
||||
|
||||
```typescript
|
||||
import { FSM } from './Framework/FSM/FSM';
|
||||
|
||||
// 1. 创建状态机
|
||||
const fsm = new FSM();
|
||||
|
||||
// 2. 添加状态
|
||||
fsm.addState(new IdleState(fsm));
|
||||
fsm.addState(new MoveState(fsm));
|
||||
fsm.addState(new AttackState(fsm));
|
||||
|
||||
// 3. 切换到初始状态
|
||||
fsm.changeState("Idle");
|
||||
|
||||
// 4. 在游戏主循环中更新
|
||||
function update(dt: number) {
|
||||
fsm.update(dt);
|
||||
}
|
||||
|
||||
// 5. 切换状态(可传递参数)
|
||||
fsm.changeState("Move", { speed: 10 });
|
||||
```
|
||||
|
||||
### 3. 角色 AI 示例
|
||||
|
||||
```typescript
|
||||
// 敌人 AI 状态机
|
||||
class EnemyAI {
|
||||
private _fsm: FSM;
|
||||
|
||||
constructor() {
|
||||
this._fsm = new FSM();
|
||||
|
||||
// 添加 AI 状态
|
||||
this._fsm.addState(new PatrolState(this._fsm));
|
||||
this._fsm.addState(new ChaseState(this._fsm));
|
||||
this._fsm.addState(new AttackState(this._fsm));
|
||||
this._fsm.addState(new FleeState(this._fsm));
|
||||
|
||||
// 从巡逻状态开始
|
||||
this._fsm.changeState("Patrol");
|
||||
}
|
||||
|
||||
update(dt: number): void {
|
||||
this._fsm.update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
// 巡逻状态
|
||||
class PatrolState extends BaseState {
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
console.log("敌人开始巡逻");
|
||||
}
|
||||
|
||||
onUpdate(dt: number): void {
|
||||
// 检测玩家
|
||||
if (detectPlayer()) {
|
||||
this._fsm.changeState("Chase");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 追击状态
|
||||
class ChaseState extends BaseState {
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
console.log("敌人发现玩家,开始追击");
|
||||
}
|
||||
|
||||
onUpdate(dt: number): void {
|
||||
// 靠近玩家
|
||||
moveToPlayer();
|
||||
|
||||
// 进入攻击范围
|
||||
if (inAttackRange()) {
|
||||
this._fsm.changeState("Attack");
|
||||
}
|
||||
// 玩家逃离
|
||||
else if (!canSeePlayer()) {
|
||||
this._fsm.changeState("Patrol");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 动画状态机示例
|
||||
|
||||
```typescript
|
||||
// 角色动画状态机
|
||||
class CharacterAnimFSM {
|
||||
private _fsm: FSM;
|
||||
private _animator: any; // Cocos 动画组件
|
||||
|
||||
constructor(animator: any) {
|
||||
this._animator = animator;
|
||||
this._fsm = new FSM();
|
||||
|
||||
// 添加动画状态
|
||||
this._fsm.addState(new IdleAnimState(this._fsm, this._animator));
|
||||
this._fsm.addState(new RunAnimState(this._fsm, this._animator));
|
||||
this._fsm.addState(new JumpAnimState(this._fsm, this._animator));
|
||||
this._fsm.addState(new AttackAnimState(this._fsm, this._animator));
|
||||
|
||||
this._fsm.changeState("Idle");
|
||||
}
|
||||
|
||||
// 播放动画
|
||||
play(animName: string, params?: any): void {
|
||||
this._fsm.changeState(animName, params);
|
||||
}
|
||||
}
|
||||
|
||||
// 待机动画状态
|
||||
class IdleAnimState extends BaseState {
|
||||
private _animator: any;
|
||||
|
||||
constructor(fsm: FSM, animator: any) {
|
||||
super(fsm, "Idle");
|
||||
this._animator = animator;
|
||||
}
|
||||
|
||||
onEnter(params?: any): void {
|
||||
super.onEnter(params);
|
||||
this._animator.play("idle");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔄 状态切换流程
|
||||
|
||||
```
|
||||
changeState("NewState", params)
|
||||
↓
|
||||
1. 检查新状态是否存在
|
||||
↓
|
||||
2. 如果有当前状态,调用 currentState.onExit()
|
||||
↓
|
||||
3. 切换到新状态
|
||||
↓
|
||||
4. 调用 newState.onEnter(params)
|
||||
↓
|
||||
5. 更新当前状态引用
|
||||
```
|
||||
|
||||
## 📊 状态生命周期
|
||||
|
||||
```
|
||||
[创建状态实例]
|
||||
↓
|
||||
addState(state) - 添加到状态机
|
||||
↓
|
||||
changeState("StateName") - 切换状态
|
||||
↓
|
||||
onEnter(params) - 进入状态
|
||||
↓
|
||||
onUpdate(dt) - 每帧更新(如果实现)
|
||||
↓
|
||||
[触发状态切换]
|
||||
↓
|
||||
onExit() - 退出状态
|
||||
↓
|
||||
removeState("StateName") - 从状态机移除(可选)
|
||||
```
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **状态名称唯一**: 每个状态的名称必须唯一,重复添加会覆盖
|
||||
2. **构造函数传递 FSM**: 状态类的构造函数需要接收 FSM 实例
|
||||
3. **调用 super**: 重写生命周期方法时,建议先调用 `super.xxx()`
|
||||
4. **状态切换时机**: 建议在 `onUpdate()` 中判断并切换状态
|
||||
5. **参数传递**: 切换状态时可以通过 `params` 传递数据
|
||||
6. **避免循环切换**: 注意状态切换逻辑,避免无限循环
|
||||
|
||||
## 🔍 调试技巧
|
||||
|
||||
### 启用状态日志
|
||||
|
||||
```typescript
|
||||
// BaseState 默认会输出状态切换日志
|
||||
// [FSM] Enter state: Idle
|
||||
// [FSM] Exit state: Idle
|
||||
```
|
||||
|
||||
### 获取当前状态信息
|
||||
|
||||
```typescript
|
||||
// 获取当前状态名称
|
||||
const stateName = fsm.getCurrentStateName();
|
||||
console.log(`当前状态: ${stateName}`);
|
||||
|
||||
// 获取当前状态实例
|
||||
const state = fsm.getCurrentState();
|
||||
if (state) {
|
||||
console.log(`状态实例: ${state.name}`);
|
||||
}
|
||||
```
|
||||
|
||||
### 检查状态是否存在
|
||||
|
||||
```typescript
|
||||
if (fsm.hasState("Attack")) {
|
||||
console.log("Attack 状态已添加");
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 最佳实践
|
||||
|
||||
1. **单一职责**: 每个状态只负责一种行为
|
||||
2. **状态解耦**: 状态之间通过 FSM 切换,避免直接依赖
|
||||
3. **参数传递**: 使用 `params` 在状态间传递数据
|
||||
4. **及时清理**: 不再使用的状态及时移除
|
||||
5. **文档注释**: 为每个状态类添加清晰的职责说明
|
||||
|
||||
## 📚 应用场景
|
||||
|
||||
- ✅ 游戏状态管理(Boot、Login、Game 等)
|
||||
- ✅ 角色状态控制(Idle、Move、Attack 等)
|
||||
- ✅ 敌人 AI 行为(Patrol、Chase、Attack、Flee 等)
|
||||
- ✅ 动画状态机(各种动画之间的切换)
|
||||
- ✅ UI 界面流转(各个界面之间的切换)
|
||||
- ✅ 关卡状态(Ready、Playing、Pause、GameOver 等)
|
||||
Reference in New Issue
Block a user