Files
rougelike-demo/client/.github/instructions/AppStatus-Guide.md
2025-12-14 22:37:49 +08:00

352 lines
7.6 KiB
Markdown

# AppStatus 应用状态机使用指南
## 📚 概述
AppStatus 是基于 FSM 状态机实现的应用级状态管理系统,负责管理整个游戏的状态流转。
**简化后的流程**: Boot(连接) → Login(登录) → Game(游戏世界)
## 🏗️ 项目结构
```
assets/scripts/
├── Boot/
│ └── Boot.ts # 启动组件(挂载到场景)
├── App/
│ └── AppStatus/
│ ├── AppStatusBoot.ts # 启动状态(连接服务器)
│ ├── AppStatusLogin.ts # 登录状态(调用Login API)
│ ├── AppStatusGame.ts # 游戏状态(监听广播)
│ └── AppStatusManager.ts # 状态管理器
├── Framework/
│ ├── FSM/ # 状态机框架
│ └── Net/ # 网络通信框架
└── Shared/
└── protocols/ # TSRPC协议定义
```
## 🚀 快速开始
### 1. 在场景中使用
1. 打开 Cocos Creator
2. 打开主场景 `assets/scenes/main.scene`
3. 创建一个空节点,命名为 "Boot"
4.`assets/scripts/Boot/Boot.ts` 拖拽到 Boot 节点上
5. 运行游戏
### 2. 状态流转
应用启动后会自动按以下顺序流转:
```
Boot(启动) → Login(登录) → Game(游戏世界)
↑ ↓ ↓
└───────────────────────────┘
(退出/死亡返回登录)
## 📋 各状态详解
### Boot 启动状态
**触发时机**: 应用启动时
**主要工作**:
- 初始化网络管理器
- 连接服务器
**完成后**: 自动切换到 Login 状态
### Login 登录状态
**触发时机**: Boot 状态完成后
**主要工作**:
- 显示登录界面
- 等待用户输入玩家ID
- 调用 Login API 登录
**如何触发登录**:
```typescript
// 在登录UI中调用
const loginState = AppStatusManager.getInstance()
.getCurrentState() as AppStatusLogin;
await loginState.login("player123", "玩家昵称");
```
**协议**:
- API: `Login`
- 请求: `{ playerId: string, playerName?: string }`
- 响应: `{ success: boolean, player: PlayerInfo, isNewPlayer: boolean }`
**完成后**: 登录成功后直接进入 Game 状态
### Game 游戏状态
**触发时机**: 登录成功后
**主要工作**:
- 接收登录返回的玩家信息(PlayerInfo)
- 加载游戏场景
- 创建玩家角色
- 监听服务器广播消息
- 运行游戏主循环
**监听的服务器广播**:
```typescript
// PlayerJoin - 其他玩家加入
NetManager.getInstance().listenMsg("PlayerJoin", (msg) => {
console.log(`${msg.playerName} 加入了游戏`);
// 在场景中创建其他玩家
});
// PlayerMove - 其他玩家移动
NetManager.getInstance().listenMsg("PlayerMove", (msg) => {
console.log(`${msg.playerName} 移动到 (${msg.position.x}, ${msg.position.y})`);
// 更新其他玩家位置
});
// Chat - 聊天消息
NetManager.getInstance().listenMsg("Chat", (msg) => {
console.log(`${msg.playerName}: ${msg.content}`);
// 显示聊天内容
});
```
**可用操作**:
```typescript
const gameState = AppStatusManager.getInstance()
.getCurrentState() as AppStatusGame;
// 移动(调用Move API)
await NetManager.getInstance().callApi("Move", { x: 10, y: 5 });
// 发送聊天(调用Send API)
await NetManager.getInstance().callApi("Send", { content: "Hello!" });
// 暂停/恢复游戏
gameState.pauseGame();
gameState.resumeGame();
// 玩家死亡
gameState.onPlayerDeath();
// 退出游戏(返回登录)
gameState.quitGame();
```
## 🎮 AppStatusManager API
### 获取管理器实例
```typescript
import { AppStatusManager } from './App/AppStatus/AppStatusManager';
const appManager = AppStatusManager.getInstance();
```
### 主要方法
#### start()
启动应用,从 Boot 状态开始
```typescript
appManager.start();
```
#### changeState(stateName, params?)
手动切换状态
```typescript
// 切换到登录状态
appManager.changeState("Login");
// 切换到大厅状态并传递用户信息
appManager.changeState("Lobby", {
userInfo: { userId: "123", username: "玩家" }
});
// 切换到游戏状态
appManager.changeState("Game", {
roomId: "room123",
userInfo: currentUser
});
```
#### getCurrentStateName()
获取当前状态名称
```typescript
const stateName = appManager.getCurrentStateName();
console.log(`当前状态: ${stateName}`); // 输出: "Login"
```
#### getCurrentState()
获取当前状态实例
```typescript
const currentState = appManager.getCurrentState();
if (currentState) {
console.log(`当前状态: ${currentState.name}`);
}
```
#### update(dt)
更新状态机(在游戏主循环中调用)
```typescript
// Boot.ts 中已自动处理
update(deltaTime: number) {
this._appStatusManager.update(deltaTime);
}
```
## 🔧 扩展新状态
如果需要添加新的应用状态:
### 1. 创建状态类
```typescript
import { BaseState } from "../../Framework/FSM/BaseState";
export class AppStatusNewState extends BaseState {
constructor(fsm: any) {
super(fsm, "NewState");
}
onEnter(params?: any): void {
super.onEnter(params);
// 进入状态的逻辑
}
onExit(): void {
super.onExit();
// 退出状态的逻辑
}
}
```
### 2. 在 AppStatusManager 中注册
```typescript
// AppStatusManager.ts
import { AppStatusNewState } from "./AppStatusNewState";
private initStates(): void {
// ... 其他状态
this._fsm.addState(new AppStatusNewState(this._fsm));
}
```
### 3. 从其他状态切换
```typescript
this._fsm.changeState("NewState", { /* 参数 */ });
```
## 💡 最佳实践
### 1. 状态间传递数据
使用 `changeState` 的第二个参数传递数据:
```typescript
// 传递数据
this._fsm.changeState("Lobby", {
userInfo: { userId: "123", username: "玩家" }
});
// 接收数据
onEnter(params?: any): void {
if (params && params.userInfo) {
this._userInfo = params.userInfo;
}
}
```
### 2. 保持状态独立
每个状态应该是独立的,不要在状态间共享可变数据,而是通过参数传递。
### 3. 异步操作处理
在状态的 `onEnter` 中处理异步操作:
```typescript
async onEnter(params?: any): Promise<void> {
super.onEnter(params);
try {
await this.loadSomething();
this._fsm.changeState("NextState");
} catch (error) {
console.error("加载失败:", error);
// 处理错误
}
}
```
### 4. 状态清理
始终在 `onExit` 中清理资源:
```typescript
onExit(): void {
super.onExit();
// 清理UI
// 取消网络监听
// 释放资源
}
```
## 🐛 调试技巧
### 1. 查看状态流转日志
所有状态切换都会在控制台输出日志:
```
[FSM] 进入状态: Boot
[AppStatusBoot] 开始初始化应用...
[FSM] 退出状态: Boot
[FSM] 进入状态: Loading
```
### 2. 查看当前状态
```typescript
console.log("当前状态:", AppStatusManager.getInstance().getCurrentStateName());
```
### 3. 直接切换到指定状态(测试用)
```typescript
// 跳过登录直接进入大厅
AppStatusManager.getInstance().changeState("Lobby", {
userInfo: { userId: "test", username: "测试用户" }
});
```
## 📝 TODO 清单
当前 AppStatus 模块已完成基础框架,但以下功能需要后续实现:
- [ ] 集成 UI 管理器
- [ ] 实现实际的服务器连接
- [ ] 实现资源预加载
- [ ] 实现房间系统
- [ ] 实现匹配系统
- [ ] 实现游戏场景加载
- [ ] 添加状态转换动画
- [ ] 添加错误处理和重试机制
## 🎯 下一步
1. 实现 UI 系统
2. 创建登录界面
3. 连接服务器
4. 实现房间和匹配功能
5. 开发游戏主逻辑
---
更新时间: 2025-12-14