Files
rougelike-demo/client/assets/scripts/App/AppStatus/README.md

397 lines
9.0 KiB
Markdown
Raw Normal View History

2025-12-14 22:41:10 +08:00
# 应用状态机 (App/AppStatus)
## 📋 模块概述
管理应用的整体状态流转,包括启动、登录、游戏等状态,基于 Framework/FSM 实现。
## 🎯 核心特性
- ✅ 应用状态流转管理
- ✅ 网络初始化
- ✅ 登录流程
- ✅ 游戏状态管理
- ✅ 状态生命周期
- ✅ 服务器消息监听
## 🗂️ 文件结构
```
App/AppStatus/
├── AppStatusManager.ts # 应用状态管理器
├── AppStatusBoot.ts # 启动状态
├── AppStatusLogin.ts # 登录状态
└── AppStatusGame.ts # 游戏状态
```
## 🔄 状态流转图
```
[启动 Boot] → [登录 Login] → [游戏 Game]
↑ ↓ ↓
└────────────┴──────────────┘
(退出/死亡返回登录)
```
## 📘 核心类详解
### AppStatusManager - 应用状态管理器
**职责**: 管理应用的整体状态流转
```typescript
class AppStatusManager {
private _fsm: FSM; // 底层状态机
// 获取单例
static getInstance(): AppStatusManager;
// 启动应用(从 Boot 状态开始)
start(): void;
// 切换状态
changeState(stateName: string, params?: any): void;
// 获取当前状态名称
getCurrentStateName(): string | null;
// 获取当前状态实例
getCurrentState(): any;
// 更新状态机(在主循环中调用)
update(dt: number): void;
// 获取底层 FSM 实例
getFSM(): FSM;
// 销毁管理器
destroy(): void;
}
```
### AppStatusBoot - 启动状态
**职责**: 初始化网络管理器并连接服务器
```typescript
class AppStatusBoot extends BaseState {
constructor(fsm: FSM);
// 进入启动状态
async onEnter(params?: any): Promise<void>;
// 初始化并连接网络
private async initAndConnectNet(): Promise<void>;
// 退出启动状态
onExit(): void;
}
```
**执行流程**:
1. 设置服务协议
2. 初始化网络配置
3. 监听网络事件
4. 连接服务器
5. 连接成功后切换到登录状态
### AppStatusLogin - 登录状态
**职责**: 显示登录界面,处理登录逻辑
```typescript
class AppStatusLogin extends BaseState {
constructor(fsm: FSM);
// 进入登录状态
async onEnter(params?: any): Promise<void>;
// 显示登录 UI
private async showLoginUI(): Promise<void>;
// 退出登录状态
onExit(): void;
}
```
**执行流程**:
1. 通过 UIMgr 加载并显示登录 UI
2. 等待用户输入账号并点击登录
3. UILogin 调用 NetManager 发送登录请求
4. 登录成功后切换到游戏状态
### AppStatusGame - 游戏状态
**职责**: 游戏主循环,处理游戏逻辑和服务器消息
```typescript
class AppStatusGame extends BaseState {
private _player: any; // 玩家信息
private _isNewPlayer: boolean; // 是否新玩家
private _isPaused: boolean; // 是否暂停
constructor(fsm: FSM);
// 进入游戏状态
async onEnter(params?: any): Promise<void>;
// 加载游戏场景
private async loadGameScene(): Promise<void>;
// 初始化游戏
private async initGame(): Promise<void>;
// 监听服务器广播消息
private listenServerMessages(): void;
// 开始游戏
private startGame(): void;
// 游戏主循环
onUpdate(dt: number): void;
// 暂停游戏
pauseGame(): void;
// 恢复游戏
resumeGame(): void;
// 玩家死亡
private onPlayerDeath(): void;
// 退出游戏(返回登录)
quitGame(): void;
// 退出游戏状态
onExit(): void;
}
```
**执行流程**:
1. 接收玩家信息
2. 加载游戏场景
3. 初始化玩家角色
4. 监听服务器广播消息
5. 开始游戏主循环
6. 处理游戏逻辑和网络消息
## 📝 使用指南
### 1. 启动应用
```typescript
import { AppStatusManager } from './App/AppStatus/AppStatusManager';
// 在 Boot 组件中启动
@ccclass('Boot')
export class Boot extends Component {
start() {
// 获取管理器实例
const appManager = AppStatusManager.getInstance();
// 启动应用
appManager.start();
}
update(deltaTime: number) {
// 在主循环中更新状态机
AppStatusManager.getInstance().update(deltaTime);
}
}
```
### 2. 切换状态
```typescript
import { AppStatusManager } from './App/AppStatus/AppStatusManager';
// 从登录状态切换到游戏状态
AppStatusManager.getInstance().changeState('Game', {
player: playerInfo,
isNewPlayer: false
});
// 从游戏状态返回登录状态
AppStatusManager.getInstance().changeState('Login');
```
### 3. 获取当前状态
```typescript
// 获取当前状态名称
const stateName = AppStatusManager.getInstance().getCurrentStateName();
console.log(`当前状态: ${stateName}`);
// 获取当前状态实例
const currentState = AppStatusManager.getInstance().getCurrentState();
```
## 🔄 完整流程示例
### 启动到游戏的完整流程
```
1. Boot 组件启动
2. AppStatusManager.start()
3. 切换到 Boot 状态
4. 初始化网络并连接服务器
5. 连接成功,切换到 Login 状态
6. 加载并显示登录 UI
7. 用户输入账号并点击登录
8. 调用 Login API
9. 登录成功,切换到 Game 状态
10. 加载游戏场景
11. 初始化玩家角色
12. 监听服务器广播消息
13. 开始游戏主循环
```
## 📡 网络协议使用
### Boot 状态
```typescript
// 配置网络
const config: NetConfig = {
serverUrl: 'http://localhost:3000',
timeout: 30000,
autoReconnect: true,
reconnectInterval: 3000,
maxReconnectTimes: 5
};
```
### Login 状态
```typescript
// 由 UILogin 调用登录 API
const result = await netManager.callApi<ReqLogin, ResLogin>('Login', {
account: account
});
// 登录成功后切换状态
if (result && result.success) {
AppStatusManager.getInstance().changeState('Game', {
player: result.player,
isNewPlayer: result.isNewPlayer
});
}
```
### Game 状态
```typescript
// 监听服务器广播
netManager.listenMsg<MsgPlayerJoin>('PlayerJoin', (msg) => {
console.log(`玩家 ${msg.playerName} 加入游戏`);
// 在场景中创建其他玩家
});
netManager.listenMsg<MsgPlayerMove>('PlayerMove', (msg) => {
console.log(`玩家 ${msg.playerName} 移动`);
// 更新其他玩家位置
});
// 发送 API
const result = await netManager.callApi<ReqMove, ResMove>('Move', {
x: targetX,
y: targetY
});
```
## ⚠️ 注意事项
1. **状态切换参数**: 切换到 Game 状态时必须传递 player 参数
2. **网络初始化**: Boot 状态必须在网络连接成功后才能切换状态
3. **资源清理**: 切换状态时注意清理前一个状态的资源
4. **消息监听**: Game 状态退出时要取消所有服务器消息监听
5. **异步处理**: 状态的 onEnter 方法是异步的,注意使用 await
## 🔍 调试技巧
### 状态切换日志
```typescript
// BaseState 会自动输出状态切换日志
// [FSM] Enter state: Boot
// [FSM] Exit state: Boot
// [FSM] Enter state: Login
```
### 网络状态日志
```typescript
// NetManager 会输出网络状态日志
// [NetManager] 网络已连接
// [NetManager] 网络已断开
// [NetManager] 正在重连...
```
### 游戏状态信息
```typescript
// 在 Game 状态中查看玩家信息
const gameState = AppStatusManager.getInstance()
.getCurrentState() as AppStatusGame;
console.log('玩家信息:', gameState._player);
console.log('是否新玩家:', gameState._isNewPlayer);
```
## 💡 最佳实践
1. **单一入口**: 通过 AppStatusManager 统一管理所有状态切换
2. **参数传递**: 使用 params 在状态间传递必要的数据
3. **资源管理**: 每个状态负责自己的资源加载和释放
4. **错误处理**: 网络错误时提供友好的提示并返回合适的状态
5. **状态独立**: 每个状态保持独立,避免直接依赖其他状态
## 🎯 扩展状态
### 添加新状态
```typescript
// 1. 创建新状态类
class AppStatusLobby extends BaseState {
constructor(fsm: FSM) {
super(fsm, "Lobby");
}
onEnter(params?: any): void {
super.onEnter(params);
console.log("[AppStatusLobby] 进入大厅");
// 显示大厅 UI
}
onExit(): void {
super.onExit();
// 清理大厅资源
}
}
// 2. 在 AppStatusManager 中注册
private initStates(): void {
this._fsm.addState(new AppStatusBoot(this._fsm));
this._fsm.addState(new AppStatusLogin(this._fsm));
this._fsm.addState(new AppStatusLobby(this._fsm)); // 新增
this._fsm.addState(new AppStatusGame(this._fsm));
}
// 3. 修改状态流转
// Login -> Lobby -> Game
```
## 📚 相关文档
- [Framework/FSM README](../../Framework/FSM/README.md) - 状态机框架
- [Framework/Net README](../../Framework/Net/README.md) - 网络通信
- [App/Login README](../Login/README.md) - 登录模块