简单应用状态机

This commit is contained in:
janing
2025-12-14 22:41:10 +08:00
parent b0938a9fb8
commit b9573b3ad4
11 changed files with 950 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "4c66e5c4-282b-45bd-b8a0-ec4a9a08c7ec",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,61 @@
import { BaseState } from "../../Framework/FSM/BaseState";
import { NetManager } from "../../Framework/Net/NetManager";
/**
* 应用启动状态
* 职责:
* - 初始化游戏引擎
* - 加载基础配置
* - 初始化网络管理器
* - 准备第一个UI界面
*/
export class AppStatusBoot extends BaseState {
constructor(fsm: any) {
super(fsm, "Boot");
}
/**
* 进入启动状态
*/
async onEnter(params?: any): Promise<void> {
super.onEnter(params);
console.log("[AppStatusBoot] 开始初始化应用...");
try {
// 1. 初始化并连接网络
await this.initAndConnectNet();
// 2. 初始化完成,切换到登录状态
console.log("[AppStatusBoot] 启动完成,切换到登录状态");
this._fsm.changeState("Login");
} catch (error) {
console.error("[AppStatusBoot] 初始化失败:", error);
}
}
/**
* 初始化并连接网络
*/
private async initAndConnectNet(): Promise<void> {
console.log("[AppStatusBoot] 初始化网络管理器...");
// TODO: 从配置文件读取服务器地址
// import { serviceProto } from '../../Shared/protocols/serviceProto';
// const netManager = NetManager.getInstance();
// netManager.setServiceProto(serviceProto);
// netManager.init({ serverUrl: 'http://localhost:3000' });
// await netManager.connect();
console.log("[AppStatusBoot] 网络连接完成(待配置)");
}
/**
* 退出启动状态
*/
onExit(): void {
super.onExit();
console.log("[AppStatusBoot] 离开启动状态");
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "6a737e69-0f9a-47d8-b836-f3d8f586fcaa",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,211 @@
import { BaseState } from "../../Framework/FSM/BaseState";
/**
* 应用游戏状态
* 职责:
* - 加载游戏场景
* - 初始化玩家角色
* - 监听服务器广播(其他玩家加入、移动等)
* - 游戏主循环
*/
export class AppStatusGame extends BaseState {
private _player: any = null;
private _isNewPlayer: boolean = false;
constructor(fsm: any) {
super(fsm, "Game");
}
/**
* 进入游戏状态
*/
async onEnter(params?: any): Promise<void> {
super.onEnter(params);
console.log("[AppStatusGame] 进入游戏世界");
// 保存玩家信息
if (params) {
this._player = params.player || null;
this._isNewPlayer = params.isNewPlayer || false;
console.log(`[AppStatusGame] 玩家信息:`, this._player);
console.log(`[AppStatusGame] 是否新玩家: ${this._isNewPlayer}`);
}
try {
// 1. 加载游戏场景
await this.loadGameScene();
// 2. 初始化游戏
await this.initGame();
// 3. 开始监听服务器广播
this.listenServerMessages();
// 4. 开始游戏
this.startGame();
} catch (error) {
console.error("[AppStatusGame] 进入游戏失败:", error);
// 返回登录
this._fsm.changeState("Login");
}
}
/**
* 加载游戏场景
*/
private async loadGameScene(): Promise<void> {
console.log("[AppStatusGame] 加载游戏场景...");
// TODO: 使用Cocos场景管理器加载游戏场景
// await director.loadScene("GameScene");
// 模拟加载延迟
await this.delay(500);
console.log("[AppStatusGame] 游戏场景加载完成(待实现)");
}
/**
* 初始化游戏
*/
private async initGame(): Promise<void> {
console.log("[AppStatusGame] 初始化游戏...");
// TODO: 初始化游戏逻辑
// - 创建玩家角色(根据this._player信息)
// - 设置玩家位置(this._player.position)
// - 创建敌人
// - 初始化游戏规则
console.log("[AppStatusGame] 游戏初始化完成(待实现)");
}
/**
* 监听服务器广播消息
*/
private listenServerMessages(): void {
console.log("[AppStatusGame] 开始监听服务器广播...");
// TODO: 监听服务器广播消息
// const netManager = NetManager.getInstance();
// 监听玩家加入 (MsgPlayerJoin)
// netManager.listenMsg("PlayerJoin", (msg) => {
// console.log("玩家加入:", msg.playerName);
// // 在场景中创建其他玩家
// });
// 监听玩家移动 (MsgPlayerMove)
// netManager.listenMsg("PlayerMove", (msg) => {
// console.log("玩家移动:", msg.playerName, msg.position);
// // 更新其他玩家位置
// });
// 监听聊天消息 (MsgChat)
// netManager.listenMsg("Chat", (msg) => {
// console.log("聊天消息:", msg);
// // 显示聊天内容
// });
console.log("[AppStatusGame] 服务器广播监听已设置(待实现)");
}
/**
* 开始游戏
*/
private startGame(): void {
console.log("[AppStatusGame] 游戏开始!");
// TODO: 启动游戏逻辑
// - 显示游戏UI
// - 开始接收输入
// - 开始游戏主循环(在onUpdate中)
}
/**
* 更新游戏状态(每帧调用)
*/
onUpdate(dt: number): void {
// TODO: 游戏主循环逻辑
// - 更新角色位置
// - 检测碰撞
// - 更新敌人AI
// - 同步网络状态
}
/**
* 暂停游戏
*/
pauseGame(): void {
console.log("[AppStatusGame] 游戏暂停");
// TODO: 暂停游戏逻辑
// - 停止游戏更新
// - 显示暂停菜单
}
/**
* 恢复游戏
*/
resumeGame(): void {
console.log("[AppStatusGame] 游戏恢复");
// TODO: 恢复游戏逻辑
// - 继续游戏更新
// - 隐藏暂停菜单
}
/**
* 玩家死亡
*/
onPlayerDeath(): void {
console.log("[AppStatusGame] 玩家死亡");
// TODO: 处理玩家死亡
// - 显示死亡界面
// - 显示复活选项或返回登录
// 延迟后返回登录
setTimeout(() => {
this._fsm.changeState("Login");
}, 3000);
}
/**
* 退出游戏(返回登录)
*/
quitGame(): void {
console.log("[AppStatusGame] 退出游戏");
// TODO: 断开连接或通知服务器
// const netManager = NetManager.getInstance();
// await netManager.disconnect();
// 返回登录
this._fsm.changeState("Login");
}
/**
* 延迟辅助函数
*/
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* 退出游戏状态
*/
onExit(): void {
super.onExit();
console.log("[AppStatusGame] 离开游戏状态");
// TODO: 清理游戏资源
// - 卸载游戏场景
// - 清理角色对象
// - 取消服务器消息监听
// const netManager = NetManager.getInstance();
// netManager.unlistenMsg("PlayerJoin");
// netManager.unlistenMsg("PlayerMove");
// netManager.unlistenMsg("Chat");
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "fb4c25d0-b65c-4881-9997-5e3bd5d50325",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,121 @@
import { BaseState } from "../../Framework/FSM/BaseState";
import { NetManager } from "../../Framework/Net/NetManager";
import { UIMgr } from "../../Framework/UI/UIMgr";
import { UILogin } from "../Login/UILogin";
/**
* 应用登录状态
* 职责:
* - 显示登录界面
* - 处理玩家ID输入
* - 发送登录请求(Login API)
* - 登录成功后直接进入游戏世界
*/
export class AppStatusLogin extends BaseState {
constructor(fsm: any) {
super(fsm, "Login");
}
/**
* 进入登录状态
*/
async onEnter(params?: any): Promise<void> {
super.onEnter(params);
console.log("[AppStatusLogin] 显示登录界面");
// 1. 显示登录界面
await this.showLoginUI();
// 2. 等待用户输入玩家ID并点击登录
// 在 UI 中处理输入,调用 this.login(playerId, playerName)
}
/**
* 显示登录界面
*/
private async showLoginUI(): Promise<void> {
console.log("[AppStatusLogin] 加载登录UI...");
try {
const uiMgr = UIMgr.getInstance();
await uiMgr.load(UILogin);
console.log("[AppStatusLogin] 登录UI加载成功");
} catch (error) {
console.error("[AppStatusLogin] 登录UI加载失败:", error);
}
}
/**
* 执行登录
* @param playerId 玩家ID(用于识别玩家)
* @param playerName 玩家昵称(可选,新玩家时使用)
*/
async login(playerId: string, playerName?: string): Promise<void> {
console.log(`[AppStatusLogin] 尝试登录, 玩家ID: ${playerId}`);
if (!playerId || playerId.trim().length === 0) {
console.error("[AppStatusLogin] 玩家ID不能为空");
// TODO: 显示错误提示
return;
}
try {
// 1. 发送登录请求到服务器
// const netManager = NetManager.getInstance();
// const result = await netManager.callApi("Login", {
// playerId,
// playerName
// });
// 模拟登录请求
await this.delay(500);
const mockResult = {
success: true,
message: "登录成功",
player: {
id: playerId,
name: playerName || `Player_${playerId}`,
position: { x: 0, y: 0, z: 0 },
spawnPoint: { x: 0, y: 0, z: 0 },
hp: 100,
maxHp: 100,
isAlive: true,
createdAt: Date.now(),
lastLoginAt: Date.now()
},
isNewPlayer: false
};
console.log("[AppStatusLogin] 登录成功,玩家信息:", mockResult.player);
// 2. 登录成功后直接进入游戏状态
this._fsm.changeState("Game", {
player: mockResult.player,
isNewPlayer: mockResult.isNewPlayer
});
} catch (error) {
console.error("[AppStatusLogin] 登录失败:", error);
// TODO: 显示错误提示
}
}
/**
* 延迟辅助函数
*/
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* 退出登录状态
*/
onExit(): void {
super.onExit();
console.log("[AppStatusLogin] 离开登录状态");
// 隐藏登录界面
const uiMgr = UIMgr.getInstance();
uiMgr.hide(UILogin);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "f0f1f913-0bf0-440c-9b66-9712ed982479",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,107 @@
import { FSM } from "../../Framework/FSM/FSM";
import { AppStatusBoot } from "./AppStatusBoot";
import { AppStatusLogin } from "./AppStatusLogin";
import { AppStatusGame } from "./AppStatusGame";
/**
* 应用状态管理器
* 职责:
* - 管理应用的整体状态流转
* - 提供单例访问
* - 初始化所有应用状态
*
* 状态流程: Boot -> Login -> Game
*/
export class AppStatusManager {
private static _instance: AppStatusManager | null = null;
private _fsm: FSM;
/**
* 构造函数(私有)
*/
private constructor() {
this._fsm = new FSM();
this.initStates();
}
/**
* 获取单例
*/
static getInstance(): AppStatusManager {
if (!this._instance) {
this._instance = new AppStatusManager();
}
return this._instance;
}
/**
* 初始化所有状态
*/
private initStates(): void {
console.log("[AppStatusManager] 初始化应用状态...");
// 添加应用状态: Boot -> Login -> Game
this._fsm.addState(new AppStatusBoot(this._fsm));
this._fsm.addState(new AppStatusLogin(this._fsm));
this._fsm.addState(new AppStatusGame(this._fsm));
console.log("[AppStatusManager] 应用状态初始化完成");
}
/**
* 启动应用
* 从Boot状态开始
*/
start(): void {
console.log("[AppStatusManager] 启动应用...");
this._fsm.changeState("Boot");
}
/**
* 切换状态
* @param stateName 状态名称
* @param params 可选参数
*/
changeState(stateName: string, params?: any): void {
this._fsm.changeState(stateName, params);
}
/**
* 获取当前状态名称
*/
getCurrentStateName(): string | null {
return this._fsm.getCurrentStateName();
}
/**
* 获取当前状态
*/
getCurrentState(): any {
return this._fsm.getCurrentState();
}
/**
* 更新状态机(在主循环中调用)
* @param dt 距离上一帧的时间增量(秒)
*/
update(dt: number): void {
this._fsm.update(dt);
}
/**
* 获取状态机实例
* 用于高级操作
*/
getFSM(): FSM {
return this._fsm;
}
/**
* 销毁管理器
*/
destroy(): void {
console.log("[AppStatusManager] 销毁应用状态管理器");
this._fsm.clear();
AppStatusManager._instance = null;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "191d542e-df2a-43a0-998c-4daefe65c598",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,396 @@
# 应用状态机 (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) - 登录模块

View File

@@ -0,0 +1,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "4602b30b-05bf-465d-8537-b3afbbc83fb0",
"files": [],
"subMetas": {},
"userData": {}
}