diff --git a/.gitignore b/.gitignore index 0af181c..6e431e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,58 @@ # Godot 4+ specific ignores .godot/ /android/ + +# Python cache files +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python +*.so + +# IDE and editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Godot executable files (should not be in version control) +Godot/ +*.exe +*.app +*.dmg + +# Logs and temporary files +*.log +*.tmp +*.temp + +# Build outputs +build/ +dist/ +*.zip +*.tar.gz + +# Environment files +.env +.env.local +.env.*.local + +# Test coverage reports +coverage/ +*.coverage +.nyc_output/ + +# Dependency directories +node_modules/ +vendor/ diff --git a/README.md b/README.md index 24f1063..ad8b357 100644 --- a/README.md +++ b/README.md @@ -1,101 +1,274 @@ -# whaleTown +# 🐋 whaleTown -一个使用 Godot 4.5 引擎开发的游戏项目。 +一个使用 Godot 4.5 引擎开发的现代化像素游戏项目,集成了完整的用户认证系统和API接口。 -## 项目信息 +## 🎮 项目信息 -- **引擎版本**: Godot 4.5 +- **引擎版本**: Godot 4.5.1 - **渲染器**: Forward Plus -- **项目类型**: 2D 游戏 +- **项目类型**: 2D 像素游戏 +- **架构模式**: 模块化 + 事件驱动 +- **后端集成**: RESTful API + 用户认证 -## 项目结构 +## 🚀 快速开始 -``` -whaleTown/ -├── addons/ # Godot 插件目录 -├── assets/ # 游戏资源文件(图片、音频等) -├── data/ # 游戏数据文件(配置、关卡数据等) -├── docs/ # 项目文档 -├── scenes/ # 游戏场景文件 -│ └── main_scene.tscn # 主场景 -├── scripts/ # GDScript 脚本文件 -├── tests/ # 测试文件 -├── icon.svg # 项目图标 -└── project.godot # Godot 项目配置文件 -``` - -## 开始使用 - -### 前置要求 - -- [Godot Engine 4.5](https://godotengine.org/download) 或更高版本 +### 环境要求 +- [Godot Engine 4.5+](https://godotengine.org/download) +- Python 3.7+ (用于API测试) ### 运行项目 - -1. 克隆或下载此项目 -2. 使用 Godot 编辑器打开项目 -3. 在编辑器中点击"运行"按钮或按 F5 键启动游戏 - -### 开发指南 - -- **场景文件**: 所有场景文件存放在 `scenes/` 目录 -- **脚本文件**: 所有 GDScript 脚本存放在 `scripts/` 目录 -- **资源文件**: 图片、音频等资源存放在 `assets/` 目录 -- **游戏数据**: 配置文件、关卡数据等存放在 `data/` 目录 - -### 命名规范 - -本项目遵循统一的命名规范以保持代码一致性: - -**核心规则**: - -- **场景文件**:`下划线_scene.tscn` 或 `下划线_prefab.tscn` - - 示例:`main_scene.tscn`、`player_prefab.tscn` -- **脚本文件**:`PascalCase.gd`(大驼峰) - - 示例:`PlayerController.gd`、`UI_MainMenu.gd` -- **节点名称**:`camelCase`(小驼峰) - - 示例:`playerHpBar`、`startButton` -- **变量/函数**:`camelCase`(小驼峰) - - 示例:`var moveSpeed`、`func getPlayerPos()` -- **常量**:`UPPER_CASE`(全大写 + 下划线) - - 示例:`const MAX_HEALTH = 100` -- **资源文件**:`lower_case`(小写 + 下划线) - - 示例:`bg_main_menu.png`、`sound_jump.wav` - -📖 查看完整的 [命名规范文档](docs/naming_convention.md) - -### Git 提交规范 - -本项目遵循统一的 Git 提交信息格式:`<类型>:<描述>` - -**常用提交类型**: - -- `init`:项目初始化 -- `feat`:新增功能 -- `fix`:修复 Bug -- `docs`:文档更新 -- `scene`:场景文件相关 -- `asset`:资源文件相关 -- `ui`:UI 界面相关 -- `gameplay`:游戏玩法相关 -- `refactor`:代码重构 -- `perf`:性能优化 - -**提交示例**: - ```bash -git commit -m "init:项目初始化,搭建Godot文件结构" -git commit -m "feat:实现玩家角色的移动和跳跃" -git commit -m "fix:修复敌人穿墙的碰撞问题" -git commit -m "scene:创建战斗场景并配置相机" +# 1. 克隆项目 +git clone +cd whale-town + +# 2. 使用Godot编辑器打开项目 +# 3. 按F5运行或点击"运行"按钮 + +# 4. 测试API接口(可选) +python tests/api/simple_api_test.py ``` -📖 查看完整的 [Git 提交规范文档](docs/git_commit_guide.md) +## 🏗️ 项目架构 -## 贡献 +### 核心设计理念 +- **场景独立性** - 每个场景都是独立的功能模块 +- **高度解耦** - 通过事件系统和管理器通信 +- **组件复用** - 可复用组件统一管理 +- **标准化** - 统一的命名规范和目录结构 +- **测试驱动** - 完整的测试体系和文档 -欢迎提交 Issue 和 Pull Request! +### 目录结构 +``` +whaleTown/ +├── 🎬 scenes/ # 游戏场景 +│ ├── auth_scene.tscn # 用户认证场景 +│ ├── main_scene.tscn # 主游戏场景 +│ └── prefabs/ # 预制体组件 +├── 🔧 core/ # 核心系统(自动加载) +│ ├── managers/ # 全局管理器 +│ ├── systems/ # 系统组件 +│ └── utils/ # 工具类 +├── 📝 scripts/ # 业务逻辑脚本 +│ ├── scenes/ # 场景脚本 +│ ├── network/ # 网络相关 +│ └── ui/ # UI组件脚本 +├── 🧩 module/ # 可复用模块 +│ ├── UI/ # UI组件模块 +│ ├── Character/ # 角色模块 +│ ├── Combat/ # 战斗模块 +│ ├── Dialogue/ # 对话模块 +│ └── Inventory/ # 背包模块 +├── 🎨 assets/ # 游戏资源 +│ ├── sprites/ # 精灵图资源 +│ ├── audio/ # 音频文件 +│ ├── ui/ # UI界面资源 +│ ├── fonts/ # 字体资源 +│ ├── materials/ # 材质资源 +│ └── shaders/ # 着色器资源 +├── 📊 data/ # 配置数据 +│ ├── configs/ # 游戏配置 +│ ├── localization/ # 本地化文件 +│ ├── characters/ # 角色数据 +│ ├── items/ # 物品数据 +│ ├── levels/ # 关卡数据 +│ └── dialogues/ # 对话数据 +├── 🧪 tests/ # 测试文件 +│ ├── api/ # API接口测试 +│ ├── auth/ # 认证UI测试 +│ ├── unit/ # 单元测试 +│ ├── integration/ # 集成测试 +│ └── performance/ # 性能测试 +└── 📚 docs/ # 项目文档 + ├── auth/ # 认证相关文档 + ├── api-documentation.md # API接口文档 + ├── project_structure.md # 项目结构说明 + ├── naming_convention.md # 命名规范 + ├── code_comment_guide.md # 代码注释规范 + └── git_commit_guide.md # Git提交规范 +``` -## 许可证 +### 核心系统 +项目包含以下自动加载的核心系统: -[在此添加许可证信息] +- **GameManager** - 全局游戏状态管理 +- **SceneManager** - 场景切换管理 +- **EventSystem** - 事件通信系统 + +使用示例: +```gdscript +# 状态管理 +GameManager.change_state(GameManager.GameState.IN_GAME) + +# 场景切换 +SceneManager.change_scene("battle") + +# 事件通信 +EventSystem.emit_event("player_health_changed", 80) +EventSystem.connect_event("player_died", _on_player_died) +``` + +## ✨ 主要功能 + +### 🔐 用户认证系统 +- **用户注册** - 支持邮箱验证码验证 +- **用户登录** - 多种登录方式(用户名/邮箱/手机号) +- **密码管理** - 密码重置和修改功能 +- **GitHub OAuth** - 第三方登录集成 +- **错误处理** - 完整的错误提示和频率限制 + +### 🎮 游戏功能 +- **主场景** - 游戏主界面和菜单系统 +- **认证场景** - 完整的登录注册界面 +- **状态管理** - 用户状态和游戏状态管理 +- **网络通信** - RESTful API集成 + +### 🧪 测试体系 +- **API测试** - 完整的接口测试脚本 +- **UI测试** - 认证界面的交互测试 +- **错误场景** - 边界条件和异常处理测试 + +## 🔧 开发规范 + +### 命名规范 +- **场景文件**: `snake_case_scene.tscn` (如: `auth_scene.tscn`) +- **脚本文件**: `PascalCase.gd` (如: `AuthScene.gd`) +- **节点名称**: `camelCase` (如: `loginButton`) +- **变量/函数**: `camelCase` (如: `playerHealth`) +- **常量**: `UPPER_CASE` (如: `MAX_HEALTH`) +- **资源文件**: `snake_case` (如: `bg_auth_scene.png`) + +### 代码注释规范 +- **文件头注释**: 说明文件用途、主要功能和依赖关系 +- **函数注释**: 包含参数说明、返回值和使用示例 +- **复杂逻辑**: 添加行内注释解释业务逻辑和设计决策 +- **特殊标记**: 使用 TODO、FIXME、NOTE 等标准标记 +- **AI辅助**: 支持AI补充注释,提供详细的上下文信息 + +### Git 提交规范 +使用格式:`<类型>:<描述>` + +常用类型:`feat` `fix` `docs` `refactor` `scene` `asset` `ui` `test` + +```bash +git commit -m "feat:实现用户登录功能" +git commit -m "fix:修复429错误处理" +git commit -m "test:添加API接口测试" +git commit -m "docs:更新项目文档" +``` + +## 📚 项目文档 + +### 核心文档 +- 📋 [项目结构详解](docs/project_structure.md) - 完整的架构说明 +- 📝 [命名规范](docs/naming_convention.md) - 详细的命名规则 +- 💬 [代码注释规范](docs/code_comment_guide.md) - 注释标准和AI辅助指南 +- 🔀 [Git提交规范](docs/git_commit_guide.md) - 提交信息标准 + +### API和测试文档 +- 🔌 [API接口文档](docs/api-documentation.md) - 完整的API说明和测试指南 +- 🔐 [认证系统文档](docs/auth/) - 用户认证相关文档 +- 🧪 [API测试指南](tests/api/README.md) - API测试使用方法 +- 🎮 [认证UI测试](tests/auth/README.md) - UI测试场景说明 + +## 🛠️ 开发指南 + +### 添加新场景 +1. 在 `scenes/` 创建场景文件 +2. 在 `scripts/scenes/` 创建对应脚本 +3. 在 `SceneManager` 中注册场景路径 +4. 使用 `SceneManager.change_scene()` 切换 + +### 创建可复用组件 +1. 在 `module/` 对应分类下创建组件 +2. 实现标准接口 +3. 通过 `EventSystem` 与其他模块通信 +4. 在 `scenes/prefabs/` 创建预制体 + +### 资源管理 +- 图片资源放入 `assets/sprites/` 对应分类 +- 音频文件放入 `assets/audio/` 对应分类 +- UI资源放入 `assets/ui/` 对应分类 +- 配置文件放入 `data/configs/` +- 遵循命名规范,使用英文小写+下划线 + +### API接口测试 +项目提供了完整的Python测试脚本来验证API接口: + +```bash +# 快速测试API连通性 +python tests/api/simple_api_test.py + +# 完整的API功能测试 +python tests/api/api_test.py --verbose + +# 自定义服务器地址测试 +python tests/api/simple_api_test.py https://your-api-server.com +``` + +测试脚本会验证: +- ✅ 应用状态检查 +- ✅ 用户注册和登录功能 +- ✅ 邮箱验证码发送和验证 +- ✅ 错误处理和频率限制(429错误) +- ✅ 管理员功能和权限控制 +- ✅ 用户状态管理 +- ✅ 安全功能测试 + +📖 查看 [API测试文档](tests/api/README.md) 了解详细使用方法 + +### 认证UI测试 +项目还提供了Godot内置的UI测试场景: + +1. 在Godot编辑器中打开 `tests/auth/auth_ui_test.tscn` +2. 运行场景进行交互式测试 +3. 测试各种错误场景和边界条件 + +📖 查看 [认证UI测试文档](tests/auth/README.md) 了解详细使用方法 + +## 🔧 技术栈 + +- **游戏引擎**: Godot 4.5.1 +- **脚本语言**: GDScript +- **架构模式**: 模块化 + 事件驱动 +- **状态管理**: 单例管理器模式 +- **通信机制**: 全局事件系统 +- **API集成**: RESTful API + JSON +- **测试框架**: Python + Godot内置测试 + +## 🤝 贡献指南 + +1. Fork 项目 +2. 创建功能分支 (`git checkout -b feature/AmazingFeature`) +3. 遵循项目的命名规范和架构设计 +4. 添加相应的测试用例 +5. 更新相关文档 +6. 提交更改 (`git commit -m 'feat:添加某个功能'`) +7. 推送到分支 (`git push origin feature/AmazingFeature`) +8. 开启 Pull Request + +### 贡献类型 +- 🐛 Bug修复 +- ✨ 新功能开发 +- 📚 文档改进 +- 🧪 测试用例 +- 🎨 UI/UX改进 +- ⚡ 性能优化 + +## 📄 许可证 + +本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情 + +--- + +## 🎯 项目状态 + +- ✅ 基础架构搭建完成 +- ✅ 用户认证系统完成 +- ✅ API接口集成完成 +- ✅ 测试体系建立完成 +- ✅ 文档体系完善 +- 🚧 游戏核心玩法开发中 +- 🚧 更多功能模块开发中 + +**最后更新**: 2025-12-24 diff --git a/docs/.gitkeep b/docs/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docs/auth/form_validation.md b/docs/auth/form_validation.md new file mode 100644 index 0000000..a5b8a51 --- /dev/null +++ b/docs/auth/form_validation.md @@ -0,0 +1,324 @@ +# 表单验证规范文档 + +## 概述 + +本文档详细说明了登录和注册表单的验证规则、UI交互规范和错误处理机制。 + +## 验证规则 + +### 1. 用户名验证 + +#### 规则 +- **必填项**: 是 +- **长度**: 1-50字符 +- **格式**: 只能包含字母、数字和下划线 +- **正则表达式**: `^[a-zA-Z0-9_]+$` + +#### 错误提示 +- 空值: "用户名不能为空" +- 长度不符: "用户名长度应为1-50字符" +- 格式错误: "用户名只能包含字母、数字和下划线" + +### 2. 邮箱验证 + +#### 规则 +- **必填项**: 是(注册时) +- **格式**: 标准邮箱格式 +- **正则表达式**: `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$` + +#### 错误提示 +- 空值: "邮箱不能为空" +- 格式错误: "请输入有效的邮箱地址" + +### 3. 密码验证 + +#### 规则 +- **必填项**: 是 +- **长度**: 8-128字符 +- **复杂度**: 必须包含字母和数字 +- **安全性**: 不允许纯数字或纯字母 + +#### 错误提示 +- 空值: "密码不能为空" +- 长度不足: "密码长度至少8位" +- 长度超限: "密码长度不能超过128位" +- 复杂度不够: "密码必须包含字母和数字" + +### 4. 确认密码验证 + +#### 规则 +- **必填项**: 是(注册时) +- **一致性**: 必须与密码字段完全一致 + +#### 错误提示 +- 空值: "确认密码不能为空" +- 不一致: "两次输入的密码不一致" + +### 5. 验证码验证 + +#### 规则 +- **必填项**: 是(注册时) +- **长度**: 6位数字 +- **格式**: 纯数字 +- **有效性**: 必须先获取验证码 + +#### 错误提示 +- 空值: "验证码不能为空" +- 长度错误: "验证码必须是6位数字" +- 格式错误: "验证码必须是6位数字" +- 未获取: "请先获取邮箱验证码" + +## UI交互规范 + +### 1. 必填项标识 + +所有必填字段都使用水平布局来显示标签、红色星号和右对齐的错误提示: + +#### 结构设计 +``` +VBoxContainer (字段容器) +├── HBoxContainer (标签和错误提示容器) +│ ├── Label (字段名称) +│ ├── Label (红色星号 " *") +│ ├── Control (弹性空间) [size_flags_horizontal = 3] +│ └── Label (红色错误提示) [右对齐,默认隐藏] +└── LineEdit (输入框) +``` + +#### 视觉效果 +- **标签**: 黑色文本,如 "用户名"、"邮箱"、"密码" +- **星号**: 红色文本 `Color(1, 0.2, 0.2, 1)`,内容为 " *" +- **弹性空间**: Control节点,`size_flags_horizontal = 3`,占据剩余空间 +- **错误提示**: 红色文本,12px字体,右对齐显示 (`horizontal_alignment = 2`) +- **布局**: 标签和星号左对齐,错误提示右对齐 + +#### 交互行为 +- **正常状态**: 显示 `用户名 * ` +- **错误状态**: 显示 `用户名 * 用户名不能为空` +- **输入时**: 错误提示自动隐藏,回到正常状态 + +#### 优势 +- 错误提示右对齐,与输入框右边缘对齐,视觉更整齐 +- 利用弹性空间实现左右分布,布局更美观 +- 不占用额外的垂直空间 +- 避免UI布局被拉长导致溢出 +- 保持界面紧凑美观 +- 红色星号和错误提示颜色一致,视觉统一 +- 错误提示位置固定,不会因为文本长度变化而影响布局 + +### 2. 实时验证 + +#### 失焦验证 +- 当用户离开输入框时(`focus_exited`)触发验证 +- 立即显示相应的错误提示 +- 错误提示显示在输入框下方 + +#### 输入时验证 +- 当用户开始输入时(`text_changed`)隐藏错误提示 +- 提供即时的视觉反馈 +- 避免在用户输入过程中显示错误 + +### 3. 错误提示样式 + +#### 视觉设计 +- **颜色**: 红色 `Color(1, 0.2, 0.2, 1)` +- **字体大小**: 12px +- **位置**: 输入框正下方 +- **显示状态**: 默认隐藏,验证失败时显示 + +#### 错误信息特点 +- 简洁明了,直接指出问题 +- 提供解决建议 +- 使用友好的语言 + +### 4. 按钮状态管理 + +#### 发送验证码按钮 +- **正常状态**: "发送验证码" +- **冷却状态**: "重新发送(60)" (倒计时) +- **禁用状态**: 请求进行中时禁用 + +#### 提交按钮 +- **正常状态**: 可点击 +- **禁用状态**: 表单验证失败或请求进行中时禁用 +- **加载状态**: 显示"正在注册..."等提示 + +## 验证流程 + +### 1. 登录表单验证流程 + +``` +用户输入 → 失焦验证 → 显示错误(如有) → 点击登录 → 整体验证 → 提交请求 +``` + +#### 验证步骤 +1. 检查用户名是否为空 +2. 检查密码是否为空 +3. 所有验证通过后提交登录请求 + +### 2. 注册表单验证流程 + +``` +用户输入 → 失焦验证 → 显示错误(如有) → 获取验证码 → 输入验证码 → 点击注册 → 整体验证 → 邮箱验证 → 用户注册 +``` + +#### 验证步骤 +1. 验证用户名格式和长度 +2. 验证邮箱格式 +3. 验证密码强度 +4. 验证确认密码一致性 +5. 验证验证码格式和有效性 +6. 发送邮箱验证请求 +7. 验证成功后发送注册请求 + +### 3. 验证码获取流程 + +``` +输入邮箱 → 验证邮箱格式 → 检查冷却时间 → 发送验证码 → 开始冷却计时 +``` + +#### 冷却机制 +- **冷却时间**: 60秒 +- **按钮状态**: 显示倒计时 +- **重复发送**: 冷却结束后可重新发送 + +## 错误处理机制 + +### 1. 客户端验证 + +#### 即时验证 +- 在用户输入过程中提供即时反馈 +- 防止用户提交无效数据 +- 提升用户体验 + +#### 提交前验证 +- 在发送请求前进行完整验证 +- 确保所有必填项都已正确填写 +- 避免无效的网络请求 + +### 2. 服务器验证 + +#### 后端验证 +- 服务器端进行二次验证 +- 处理服务器返回的错误信息 +- 显示相应的错误提示 + +#### 网络错误处理 +- 连接失败提示 +- 超时处理 +- 服务器错误提示 + +### 3. 用户引导 + +#### 错误恢复 +- 清晰的错误提示 +- 提供解决方案 +- 引导用户正确操作 + +#### 成功反馈 +- 注册成功提示 +- 自动跳转到登录界面 +- 自动填充用户名 + +## 代码实现 + +### 1. 验证函数 + +每个字段都有对应的验证函数: +- `validate_username(username: String) -> Dictionary` +- `validate_email(email: String) -> Dictionary` +- `validate_password(password: String) -> Dictionary` +- `validate_confirm_password(password: String, confirm: String) -> Dictionary` +- `validate_verification_code(code: String) -> Dictionary` + +### 2. 事件处理 + +#### 失焦事件 +- `_on_register_username_focus_exited()` +- `_on_register_email_focus_exited()` +- `_on_register_password_focus_exited()` +- `_on_register_confirm_focus_exited()` +- `_on_verification_focus_exited()` + +#### 输入事件 +- `_on_register_username_text_changed(new_text: String)` +- `_on_register_email_text_changed(new_text: String)` +- `_on_register_password_text_changed(new_text: String)` +- `_on_register_confirm_text_changed(new_text: String)` +- `_on_verification_text_changed(new_text: String)` + +### 3. 整体验证 + +- `validate_login_form() -> bool` +- `validate_register_form() -> bool` + +## 测试用例 + +### 1. 用户名测试 + +| 输入 | 预期结果 | 错误信息 | +|------|----------|----------| +| "" | 失败 | "用户名不能为空" | +| "a" | 成功 | - | +| "test_user123" | 成功 | - | +| "test@user" | 失败 | "用户名只能包含字母、数字和下划线" | +| "a".repeat(51) | 失败 | "用户名长度应为1-50字符" | + +### 2. 邮箱测试 + +| 输入 | 预期结果 | 错误信息 | +|------|----------|----------| +| "" | 失败 | "邮箱不能为空" | +| "test@example.com" | 成功 | - | +| "invalid-email" | 失败 | "请输入有效的邮箱地址" | +| "test@" | 失败 | "请输入有效的邮箱地址" | + +### 3. 密码测试 + +| 输入 | 预期结果 | 错误信息 | +|------|----------|----------| +| "" | 失败 | "密码不能为空" | +| "1234567" | 失败 | "密码长度至少8位" | +| "12345678" | 失败 | "密码必须包含字母和数字" | +| "abcdefgh" | 失败 | "密码必须包含字母和数字" | +| "abc12345" | 成功 | - | + +### 4. 验证码测试 + +| 输入 | 预期结果 | 错误信息 | +|------|----------|----------| +| "" | 失败 | "验证码不能为空" | +| "12345" | 失败 | "验证码必须是6位数字" | +| "1234567" | 失败 | "验证码必须是6位数字" | +| "12345a" | 失败 | "验证码必须是6位数字" | +| "123456" | 成功 | - | + +## 最佳实践 + +### 1. 用户体验 + +- **即时反馈**: 在用户输入时提供即时的视觉反馈 +- **清晰提示**: 错误信息要简洁明了,易于理解 +- **引导操作**: 通过UI引导用户完成正确的操作流程 + +### 2. 性能优化 + +- **避免过度验证**: 不在每次字符输入时都进行复杂验证 +- **合理的验证时机**: 在失焦和提交时进行验证 +- **缓存验证结果**: 避免重复验证相同的内容 + +### 3. 安全考虑 + +- **客户端+服务端**: 双重验证确保数据安全 +- **敏感信息**: 密码等敏感信息不在客户端明文存储 +- **防止暴力破解**: 验证码冷却机制防止频繁请求 + +### 4. 可维护性 + +- **模块化设计**: 每个验证规则独立成函数 +- **统一的错误处理**: 使用统一的错误显示机制 +- **可配置的规则**: 验证规则可以根据需求调整 + +## 更新日志 + +- **v1.0.0** (2025-12-24): 初始版本,包含完整的表单验证规范 \ No newline at end of file diff --git a/docs/auth/testing_guide.md b/docs/auth/testing_guide.md new file mode 100644 index 0000000..e7fb94d --- /dev/null +++ b/docs/auth/testing_guide.md @@ -0,0 +1,283 @@ +# 表单验证测试指南 + +## 测试概述 + +本文档提供了完整的表单验证功能测试步骤,确保所有验证规则和用户交互都能正常工作。 + +## 测试环境准备 + +### 1. 启动后端服务 +```bash +# 确保后端服务运行在 https://whaletownend.xinghangee.icu +# 或者本地开发环境: http://localhost:3000 +npm start +# 或者你的后端启动命令 +``` + +### 2. 打开Godot项目 +- 启动Godot编辑器 +- 打开鲸鱼镇项目 +- 运行主场景 + +## 登录表单测试 + +### 测试用例1: 必填项验证 + +#### 步骤 +1. 点击"注册居民身份"进入登录界面 +2. 不输入任何内容,直接点击用户名输入框外的区域 +3. 不输入任何内容,直接点击密码输入框外的区域 +4. 点击"进入小镇"或"密码登录"按钮 + +#### 预期结果 +- 用户名输入框下方显示红色错误提示:"用户名不能为空" +- 密码输入框下方显示红色错误提示:"密码不能为空" +- 按钮点击无效,不会提交表单 + +### 测试用例2: 实时反馈 + +#### 步骤 +1. 触发上述错误提示后 +2. 在用户名输入框中输入任意字符 +3. 在密码输入框中输入任意字符 + +#### 预期结果 +- 开始输入时,对应的错误提示立即消失 +- 提供即时的视觉反馈 + +### 测试用例3: 正常登录 + +#### 步骤 +1. 输入有效的用户名:"testuser" +2. 输入任意密码:"password123" +3. 点击"进入小镇" + +#### 预期结果 +- 无错误提示显示 +- 成功进入游戏主界面 +- 显示用户名信息 + +## 注册表单测试 + +### 测试用例4: 用户名验证 + +#### 测试数据 +| 输入 | 预期结果 | 错误信息 | +|------|----------|----------| +| (空) | 失败 | "用户名不能为空" | +| "test@user" | 失败 | "用户名只能包含字母、数字和下划线" | +| "a".repeat(51) | 失败 | "用户名长度应为1-50字符" | +| "test_user123" | 成功 | 无错误提示 | + +#### 步骤 +1. 点击"注册居民身份" +2. 依次输入上述测试数据 +3. 每次输入后点击其他输入框(触发失焦验证) + +### 测试用例5: 邮箱验证 + +#### 测试数据 +| 输入 | 预期结果 | 错误信息 | +|------|----------|----------| +| (空) | 失败 | "邮箱不能为空" | +| "invalid-email" | 失败 | "请输入有效的邮箱地址" | +| "test@" | 失败 | "请输入有效的邮箱地址" | +| "test@example.com" | 成功 | 无错误提示 | + +#### 步骤 +1. 在邮箱输入框中依次输入测试数据 +2. 每次输入后点击其他输入框 + +### 测试用例6: 密码验证 + +#### 测试数据 +| 输入 | 预期结果 | 错误信息 | +|------|----------|----------| +| (空) | 失败 | "密码不能为空" | +| "1234567" | 失败 | "密码长度至少8位" | +| "12345678" | 失败 | "密码必须包含字母和数字" | +| "abcdefgh" | 失败 | "密码必须包含字母和数字" | +| "abc12345" | 成功 | 无错误提示 | + +#### 步骤 +1. 在密码输入框中依次输入测试数据 +2. 每次输入后点击其他输入框 + +### 测试用例7: 确认密码验证 + +#### 步骤 +1. 在密码框输入:"abc12345" +2. 在确认密码框输入:""(空) +3. 点击其他输入框 +4. 在确认密码框输入:"different123" +5. 点击其他输入框 +6. 在确认密码框输入:"abc12345" +7. 点击其他输入框 + +#### 预期结果 +- 步骤3: 显示"确认密码不能为空" +- 步骤5: 显示"两次输入的密码不一致" +- 步骤7: 无错误提示 + +### 测试用例8: 验证码功能 + +#### 步骤 +1. 不输入邮箱,直接点击"发送验证码" +2. 输入无效邮箱"invalid",点击"发送验证码" +3. 输入有效邮箱"test@example.com",点击"发送验证码" +4. 立即再次点击"发送验证码" +5. 在验证码输入框输入"12345"(5位) +6. 在验证码输入框输入"12345a"(包含字母) +7. 在验证码输入框输入"123456"(正确格式) + +#### 预期结果 +- 步骤1: 邮箱框显示"邮箱不能为空",聚焦到邮箱输入框 +- 步骤2: 邮箱框显示"请输入有效的邮箱地址" +- 步骤3: 显示"正在发送验证码...",按钮变为禁用状态 +- 步骤4: 显示冷却提示"请等待 XX 秒后再次发送" +- 步骤5: 验证码框显示"验证码必须是6位数字" +- 步骤6: 验证码框显示"验证码必须是6位数字" +- 步骤7: 无错误提示 + +### 测试用例9: 完整注册流程 + +#### 步骤 +1. 填写所有必填信息: + - 用户名: "testuser" + - 邮箱: "test@example.com" + - 密码: "password123" + - 确认密码: "password123" +2. 点击"发送验证码" +3. 查看控制台获取验证码 +4. 输入验证码 +5. 点击"注册"按钮 + +#### 预期结果 +- 所有验证通过,无错误提示 +- 显示"正在验证邮箱..." +- 显示"邮箱验证成功,正在注册..." +- 显示"注册成功!" +- 自动返回登录界面 +- 用户名自动填入登录表单 + +## 边界情况测试 + +### 测试用例10: 网络异常 + +#### 步骤 +1. 关闭后端服务 +2. 尝试发送验证码 +3. 尝试注册 + +#### 预期结果 +- 显示"网络连接失败,请检查服务器是否启动" +- 按钮重新启用 + +### 测试用例11: 快速操作 + +#### 步骤 +1. 快速连续点击"发送验证码"按钮 +2. 快速连续点击"注册"按钮 + +#### 预期结果 +- 按钮在请求期间被禁用 +- 防止重复提交 + +### 测试用例12: 表单切换 + +#### 步骤 +1. 在注册表单中输入信息并触发错误提示 +2. 点击"返回登录" +3. 再次点击"注册居民身份" + +#### 预期结果 +- 切换到登录界面时,注册表单状态保持 +- 再次进入注册界面时,表单被清空,错误提示被隐藏 + +## 性能测试 + +### 测试用例13: 响应速度 + +#### 步骤 +1. 快速在各个输入框之间切换 +2. 快速输入和删除文本 +3. 观察错误提示的显示和隐藏速度 + +#### 预期结果 +- 验证响应迅速,无明显延迟 +- UI更新流畅,无卡顿现象 + +## 兼容性测试 + +### 测试用例14: 不同输入法 + +#### 步骤 +1. 使用中文输入法输入用户名 +2. 使用英文输入法输入用户名 +3. 输入特殊字符 + +#### 预期结果 +- 中文字符被正确验证为无效格式 +- 英文字符正常通过验证 +- 特殊字符按规则验证 + +## 测试检查清单 + +### 功能完整性 +- [ ] 所有必填项都有红色星号标识 +- [ ] 失焦验证正常工作 +- [ ] 实时输入反馈正常 +- [ ] 错误提示准确显示 +- [ ] 验证码发送和验证功能正常 +- [ ] 注册流程完整可用 + +### 用户体验 +- [ ] 错误提示清晰易懂 +- [ ] 按钮状态管理正确 +- [ ] 表单切换流畅 +- [ ] 成功反馈及时 + +### 错误处理 +- [ ] 网络异常处理正确 +- [ ] 服务器错误处理正确 +- [ ] 边界情况处理正确 + +### 性能表现 +- [ ] 验证响应速度快 +- [ ] UI更新流畅 +- [ ] 内存使用正常 + +## 测试报告模板 + +### 测试环境 +- Godot版本: +- 操作系统: +- 后端服务状态: +- 测试时间: + +### 测试结果 +| 测试用例 | 状态 | 备注 | +|----------|------|------| +| 登录表单验证 | ✅/❌ | | +| 注册表单验证 | ✅/❌ | | +| 验证码功能 | ✅/❌ | | +| 网络异常处理 | ✅/❌ | | +| 完整注册流程 | ✅/❌ | | + +### 发现的问题 +1. 问题描述 + - 重现步骤 + - 预期结果 + - 实际结果 + - 严重程度 + +### 改进建议 +1. 功能改进 +2. 用户体验优化 +3. 性能优化 + +--- + +**测试完成日期**: ___________ +**测试人员**: ___________ +**测试版本**: v1.0.0 \ No newline at end of file diff --git a/docs/code_comment_guide.md b/docs/code_comment_guide.md new file mode 100644 index 0000000..fb37615 --- /dev/null +++ b/docs/code_comment_guide.md @@ -0,0 +1,433 @@ +# GDScript 代码注释规范 + +本文档详细说明了 whaleTown 项目中 GDScript 代码的注释规范,旨在提高代码可读性和维护性。 + +## 目录 + +- [基本原则](#基本原则) +- [文件头注释](#文件头注释) +- [类和函数注释](#类和函数注释) +- [变量注释](#变量注释) +- [行内注释](#行内注释) +- [特殊注释标记](#特殊注释标记) +- [AI辅助注释指南](#ai辅助注释指南) + +## 基本原则 + +### 注释的目的 +- **解释为什么**,而不是解释做什么 +- **提供上下文**,帮助理解代码意图 +- **记录重要决策**和设计考虑 +- **警告潜在问题**和注意事项 + +### 注释质量标准 +- 简洁明了,避免冗余 +- 使用中文,保持一致性 +- 及时更新,与代码同步 +- 避免显而易见的注释 + +## 文件头注释 + +每个 GDScript 文件都应该包含文件头注释,说明文件的用途和基本信息。 + +### 标准格式 + +```gdscript +# ============================================================================ +# 文件名: PlayerController.gd +# 作用: 玩家角色控制器,处理玩家输入和移动逻辑 +# +# 主要功能: +# - 处理键盘和手柄输入 +# - 控制角色移动和跳跃 +# - 管理角色状态切换 +# - 处理碰撞检测 +# +# 依赖: MovementComponent, AnimationComponent +# 作者: [开发者名称] +# 创建时间: 2024-12-24 +# ============================================================================ + +extends CharacterBody2D +``` + +### 管理器类文件头 + +```gdscript +# ============================================================================ +# 游戏管理器 - GameManager.gd +# +# 全局单例管理器,负责游戏状态管理和生命周期控制 +# +# 核心职责: +# - 游戏状态切换 (加载、认证、游戏中、暂停等) +# - 用户信息管理 +# - 全局配置访问 +# - 系统初始化和清理 +# +# 使用方式: +# GameManager.change_state(GameManager.GameState.IN_GAME) +# GameManager.set_current_user("player123") +# +# 注意事项: +# - 作为自动加载单例,全局可访问 +# - 状态变更会触发 game_state_changed 信号 +# ============================================================================ + +extends Node +``` +## 类和函数注释 + +### 类注释 + +```gdscript +# 玩家数据类 +# +# 存储和管理玩家的基本属性和状态信息 +# 支持数据序列化和反序列化,用于存档系统 +class_name PlayerData + +# 武器组件类 +# +# 为角色提供武器功能,包括攻击、换弹、特殊技能等 +# 可以挂载到任何具有攻击能力的角色上 +# +# 使用示例: +# var weapon = WeaponComponent.new() +# weapon.setup_weapon("sword", 50) +# add_child(weapon) +class_name WeaponComponent +``` + +### 函数注释格式 + +```gdscript +# 处理玩家输入并更新移动状态 +# +# 参数: +# delta: float - 帧时间间隔 +# +# 返回值: 无 +# +# 注意事项: +# - 需要在 _physics_process 中调用 +# - 会自动处理重力和碰撞 +func handle_movement(delta: float) -> void: + +# 验证用户输入的邮箱格式 +# +# 参数: +# email: String - 待验证的邮箱地址 +# +# 返回值: +# Dictionary - 包含验证结果和错误信息 +# { +# "valid": bool, # 是否有效 +# "message": String # 错误信息(如果无效) +# } +# +# 使用示例: +# var result = validate_email("test@example.com") +# if result.valid: +# print("邮箱格式正确") +static func validate_email(email: String) -> Dictionary: +``` +## 变量注释 + +### 成员变量注释 + +```gdscript +# 玩家基础属性 +@export var max_health: int = 100 # 最大生命值 +@export var move_speed: float = 200.0 # 移动速度 (像素/秒) +@export var jump_force: float = -400.0 # 跳跃力度 (负值向上) + +# 状态管理 +var current_health: int # 当前生命值 +var is_grounded: bool = false # 是否在地面上 +var can_double_jump: bool = true # 是否可以二段跳 + +# 节点引用 - 在 _ready() 中初始化 +@onready var sprite: Sprite2D = $Sprite2D +@onready var collision: CollisionShape2D = $CollisionShape2D +@onready var animation_player: AnimationPlayer = $AnimationPlayer + +# 私有变量 - 内部使用 +var _velocity: Vector2 = Vector2.ZERO # 当前速度向量 +var _last_direction: int = 1 # 最后面向方向 (1=右, -1=左) +``` + +### 常量注释 + +```gdscript +# 游戏配置常量 +const GRAVITY: float = 980.0 # 重力加速度 (像素/秒²) +const MAX_FALL_SPEED: float = 1000.0 # 最大下落速度 +const COYOTE_TIME: float = 0.1 # 土狼时间 (离开平台后仍可跳跃的时间) + +# 输入动作名称 +const ACTION_MOVE_LEFT: String = "move_left" +const ACTION_MOVE_RIGHT: String = "move_right" +const ACTION_JUMP: String = "jump" + +# 动画名称常量 +const ANIM_IDLE: String = "idle" +const ANIM_WALK: String = "walk" +const ANIM_JUMP: String = "jump" +const ANIM_FALL: String = "fall" +``` + +## 行内注释 + +### 复杂逻辑注释 + +```gdscript +func update_movement(delta: float): + # 处理水平移动输入 + var input_direction = Input.get_axis("move_left", "move_right") + + if input_direction != 0: + velocity.x = input_direction * move_speed + _last_direction = sign(input_direction) # 记录面向方向 + else: + # 应用摩擦力,逐渐停止 + velocity.x = move_toward(velocity.x, 0, friction * delta) + + # 应用重力 (只在空中时) + if not is_on_floor(): + velocity.y += gravity * delta + velocity.y = min(velocity.y, max_fall_speed) # 限制最大下落速度 + + # 处理跳跃输入 + if Input.is_action_just_pressed("jump"): + if is_on_floor(): + velocity.y = jump_force # 普通跳跃 + elif can_double_jump: + velocity.y = jump_force * 0.8 # 二段跳 (力度稍小) + can_double_jump = false + + # 重置二段跳能力 + if is_on_floor() and not can_double_jump: + can_double_jump = true +``` + +### 临时解决方案注释 + +```gdscript +func handle_collision(body: Node2D): + # TODO: 重构碰撞处理逻辑,当前实现过于复杂 + # FIXME: 在某些情况下会出现重复碰撞检测 + # HACK: 临时解决方案,等待 Godot 4.6 修复相关 bug + + if body.has_method("take_damage"): + # NOTE: 伤害计算需要考虑护甲和抗性 + var damage = calculate_damage(base_damage) + body.take_damage(damage) +``` +## 特殊注释标记 + +使用标准化的标记来标识不同类型的注释: + +### 标记类型 + +```gdscript +# TODO: 待实现的功能 +# TODO: 添加音效播放功能 +# TODO: 实现存档系统 + +# FIXME: 需要修复的问题 +# FIXME: 内存泄漏问题,需要及时释放资源 +# FIXME: 在低帧率下移动不流畅 + +# HACK: 临时解决方案 +# HACK: 绕过 Godot 引擎的已知 bug +# HACK: 临时方案,等待更好的实现 + +# NOTE: 重要说明 +# NOTE: 此函数会修改全局状态,谨慎使用 +# NOTE: 性能敏感代码,避免频繁调用 + +# WARNING: 警告信息 +# WARNING: 不要在 _ready() 之前调用此函数 +# WARNING: 此操作不可逆,请确认后执行 + +# OPTIMIZE: 性能优化点 +# OPTIMIZE: 可以使用对象池优化内存分配 +# OPTIMIZE: 考虑使用缓存提高查询效率 +``` + +### 版本和兼容性标记 + +```gdscript +# @since 1.0.0 - 添加基础移动功能 +# @deprecated 使用 new_movement_system() 替代 +# @godot_version 4.5+ - 需要 Godot 4.5 或更高版本 +# @platform_specific Windows/Linux - 仅在桌面平台可用 +``` + +## AI辅助注释指南 + +### 为AI提供的注释模板 + +当需要AI帮助补充注释时,请使用以下模板: + +```gdscript +# [AI_COMMENT_REQUEST] +# 请为以下函数添加详细注释,包括: +# - 功能描述 +# - 参数说明 +# - 返回值说明 +# - 使用示例 +# - 注意事项 +func complex_function(param1: String, param2: int) -> Dictionary: + # 复杂的业务逻辑... + pass +``` + +### AI注释补充规则 + +1. **保持一致性** - 遵循项目现有的注释风格 +2. **关注业务逻辑** - 重点解释业务含义,而非语法 +3. **提供上下文** - 说明函数在整个系统中的作用 +4. **标注复杂度** - 对复杂算法提供额外说明 + +### 示例:AI补充前后对比 + +**补充前:** +```gdscript +func calculate_damage(base_damage: int, armor: int, resistance: float) -> int: + var final_damage = base_damage + final_damage -= armor + final_damage *= (1.0 - resistance) + return max(1, final_damage) +``` + +**AI补充后:** +```gdscript +# 计算最终伤害值 +# +# 根据基础伤害、护甲值和抗性计算实际造成的伤害 +# 伤害计算公式: (基础伤害 - 护甲) × (1 - 抗性) +# +# 参数: +# base_damage: int - 基础伤害值 +# armor: int - 目标护甲值 (减少固定伤害) +# resistance: float - 目标抗性 (0.0-1.0, 减少百分比伤害) +# +# 返回值: +# int - 最终伤害值 (最小为1,确保至少造成1点伤害) +# +# 使用示例: +# var damage = calculate_damage(100, 20, 0.3) # 结果: 56 +# +# 注意事项: +# - 护甲为负值时会增加伤害 +# - 抗性超过1.0时可能导致负伤害,但会被限制为1 +func calculate_damage(base_damage: int, armor: int, resistance: float) -> int: + var final_damage = base_damage + final_damage -= armor # 减去护甲值 + final_damage *= (1.0 - resistance) # 应用抗性 + return max(1, final_damage) # 确保最小伤害为1 +``` +## 注释最佳实践 + +### 什么时候需要注释 + +**必须添加注释的情况:** +- 复杂的算法和业务逻辑 +- 非显而易见的设计决策 +- 临时解决方案和已知问题 +- 公共API和接口函数 +- 性能敏感的代码段 +- 平台特定或版本特定的代码 + +**不需要注释的情况:** +- 显而易见的代码 (`var count = 0 # 计数器` ❌) +- 重复函数名的注释 (`func get_name() -> String: # 获取名称` ❌) +- 过时或错误的注释 + +### 注释维护原则 + +```gdscript +# ✅ 好的注释 - 解释为什么这样做 +# 使用二分查找提高大数组的查询效率 +# 当数组长度超过100时,线性查找性能会显著下降 +func binary_search(array: Array, target: Variant) -> int: + +# ❌ 坏的注释 - 重复代码内容 +# 遍历数组查找目标值 +func linear_search(array: Array, target: Variant) -> int: +``` + +### 团队协作注释 + +```gdscript +# 多人协作时的注释规范 +class_name NetworkManager + +# @author: 张三 - 网络连接模块 +# @author: 李四 - 数据同步模块 +# @reviewer: 王五 - 代码审查 +# @last_modified: 2024-12-24 + +# 网络连接状态枚举 +# +# 定义了客户端与服务器的连接状态 +# 状态转换: DISCONNECTED -> CONNECTING -> CONNECTED -> DISCONNECTED +enum ConnectionState { + DISCONNECTED, # 未连接 + CONNECTING, # 连接中 + CONNECTED, # 已连接 + RECONNECTING # 重连中 - @added by 李四 2024-12-20 +} +``` + +## 注释检查清单 + +在提交代码前,请检查以下项目: + +### 文件级别检查 +- [ ] 文件头注释完整(文件名、作用、主要功能) +- [ ] 依赖关系说明清楚 +- [ ] 作者和创建时间已填写 + +### 函数级别检查 +- [ ] 公共函数有完整的参数和返回值说明 +- [ ] 复杂函数有使用示例 +- [ ] 特殊情况和注意事项已标注 + +### 代码级别检查 +- [ ] 复杂逻辑有行内注释说明 +- [ ] 魔法数字有常量定义和注释 +- [ ] TODO/FIXME 标记有明确的处理计划 + +### 质量检查 +- [ ] 注释内容准确,与代码一致 +- [ ] 中文表达清晰,无错别字 +- [ ] 注释格式符合项目规范 + +## 注释工具和插件 + +### Godot编辑器设置 +``` +# 在 Godot 编辑器中设置注释快捷键 +# 编辑器设置 -> 快捷键 -> 注释/取消注释: Ctrl+/ +``` + +### 推荐的注释插件 +- **GDScript Language Server** - 提供注释语法高亮 +- **Code Formatter** - 自动格式化注释 +- **Documentation Generator** - 自动生成API文档 + +--- + +## 总结 + +良好的注释是代码质量的重要组成部分。遵循本规范可以: + +1. **提高代码可读性** - 帮助团队成员快速理解代码 +2. **降低维护成本** - 减少后期修改和调试时间 +3. **促进知识传承** - 保留设计思路和业务逻辑 +4. **支持AI辅助开发** - 为AI提供更好的上下文信息 + +记住:**好的注释解释为什么,而不是做什么。** \ No newline at end of file diff --git a/docs/naming_convention.md b/docs/naming_convention.md index 2501812..558c113 100644 --- a/docs/naming_convention.md +++ b/docs/naming_convention.md @@ -404,6 +404,37 @@ FONT_MAIN.ttf - 全部使用小写字母 - 同系列资源使用数字后缀,如 `tile_01.png`、`tile_02.png` +### 扩展资源类型 + +``` +✅ 正确 +# 材质资源 +material_metal.tres # 金属材质 +material_wood.tres # 木材材质 +material_water.tres # 水材质 + +# 着色器资源 +shader_water.gdshader # 水着色器 +shader_fire.gdshader # 火焰着色器 +shader_outline.gdshader # 轮廓着色器 + +# 特效资源 +fx_explosion.png # 爆炸特效 +fx_magic_circle.png # 魔法阵特效 +fx_damage_numbers.png # 伤害数字特效 + +# 环境资源 +obj_tree.png # 树木对象 +obj_rock.png # 岩石对象 +tile_grass_01.png # 草地瓦片 +tile_stone_01.png # 石头瓦片 + +❌ 错误 +MetalMaterial.tres # 不使用大驼峰 +material-wood.tres # 不使用连字符 +SHADER_WATER.gdshader # 不使用全大写 +``` + --- ## 目录结构 @@ -421,11 +452,33 @@ assets/ # 资源目录 sounds/ # 音效 music/ # 音乐 fonts/ # 字体 + materials/ # 材质 + shaders/ # 着色器 data/ # 数据目录 levels/ # 关卡数据 configs/ # 配置文件 + dialogues/ # 对话数据 + localization/ # 本地化数据 +core/ # 核心系统目录 + managers/ # 管理器 + systems/ # 系统组件 + utils/ # 工具类 + components/ # 通用组件 + interfaces/ # 接口定义 +module/ # 模块目录 + UI/ # UI模块 + Character/ # 角色模块 + Inventory/ # 背包模块 + Combat/ # 战斗模块 + Dialogue/ # 对话模块 addons/ # 插件目录 tests/ # 测试目录 + unit/ # 单元测试 + integration/ # 集成测试 + ui/ # UI测试 + performance/ # 性能测试 +docs/ # 文档目录 + auth/ # 认证相关文档 ❌ 错误 Scenes/ # 不使用大写 diff --git a/docs/project_structure.md b/docs/project_structure.md new file mode 100644 index 0000000..461ee0b --- /dev/null +++ b/docs/project_structure.md @@ -0,0 +1,505 @@ +# Godot 项目结构说明 + +本文档详细说明了 whaleTown 项目的文件结构设计,采用"场景+通用工具+其他"的架构模式,确保每个场景清晰独立且高度解耦。 + +## 设计理念 + +### 核心原则 +- **场景独立性**:每个场景都是独立的功能模块,可以单独开发和测试 +- **高度解耦**:场景之间通过事件系统和管理器进行通信,避免直接依赖 +- **组件复用**:可复用的组件放在通用模块中,提高开发效率 +- **资源管理**:统一的资源管理和命名规范,便于维护 + +## 项目架构概览 + +``` +whaleTown/ +├── 🎬 scenes/ # 场景层:独立的游戏场景 +├── 🔧 core/ # 核心层:通用工具和系统 +├── 🎨 assets/ # 资源层:静态资源文件 +├── 📊 data/ # 数据层:配置和游戏数据 +├── 📝 scripts/ # 脚本层:业务逻辑代码 +├── 🧩 module/ # 模块层:可复用组件 +├── 🧪 tests/ # 测试层:单元测试和集成测试 +└── 📚 docs/ # 文档层:项目文档 +``` + +## 1. 场景层 (scenes/) + +场景层包含所有独立的游戏场景,每个场景都是完整的功能模块。 + +### 1.1 场景分类 + +#### 主要场景 (Main Scenes) +``` +scenes/ +├── main_scene.tscn # 主场景:游戏入口 +├── auth_scene.tscn # 认证场景:登录注册 +├── menu_scene.tscn # 菜单场景:主菜单界面 +├── game_scene.tscn # 游戏场景:主要游戏玩法 +├── battle_scene.tscn # 战斗场景:战斗系统 +├── inventory_scene.tscn # 背包场景:物品管理 +├── shop_scene.tscn # 商店场景:购买系统 +└── settings_scene.tscn # 设置场景:游戏设置 +``` + +#### 预制体场景 (Prefabs) +``` +scenes/prefabs/ +├── ui/ +│ ├── dialog_prefab.tscn # 对话框预制体 +│ ├── button_prefab.tscn # 按钮预制体 +│ ├── health_bar_prefab.tscn # 血条预制体 +│ └── notification_prefab.tscn # 通知预制体 +├── characters/ +│ ├── player_prefab.tscn # 玩家角色预制体 +│ ├── npc_prefab.tscn # NPC预制体 +│ └── enemy_prefab.tscn # 敌人预制体 +├── items/ +│ ├── weapon_prefab.tscn # 武器预制体 +│ ├── consumable_prefab.tscn # 消耗品预制体 +│ └── collectible_prefab.tscn # 收集品预制体 +└── effects/ + ├── explosion_prefab.tscn # 爆炸特效预制体 + ├── particle_prefab.tscn # 粒子特效预制体 + └── damage_text_prefab.tscn # 伤害数字预制体 +``` + +### 1.2 场景设计原则 + +- **单一职责**:每个场景只负责一个主要功能 +- **独立运行**:场景可以独立启动和测试 +- **标准接口**:场景间通过标准化接口通信 +- **资源隔离**:场景相关资源放在对应子目录 +## 2. 核心层 (core/) + +核心层提供通用的工具类、管理器和系统组件,为整个项目提供基础服务。 + +### 2.1 核心系统结构 + +``` +core/ +├── managers/ # 管理器系统 +│ ├── GameManager.gd # 游戏管理器:全局游戏状态 +│ ├── SceneManager.gd # 场景管理器:场景切换 +│ ├── AudioManager.gd # 音频管理器:音效音乐 +│ ├── InputManager.gd # 输入管理器:输入处理 +│ ├── SaveManager.gd # 存档管理器:数据存储 +│ ├── UIManager.gd # UI管理器:界面管理 +│ └── NetworkManager.gd # 网络管理器:网络通信 +├── systems/ # 系统组件 +│ ├── EventSystem.gd # 事件系统:全局事件 +│ ├── StateMachine.gd # 状态机系统 +│ ├── ObjectPool.gd # 对象池系统 +│ ├── ResourceLoader.gd # 资源加载系统 +│ └── LocalizationSystem.gd # 本地化系统 +├── utils/ # 工具类 +│ ├── MathUtils.gd # 数学工具 +│ ├── StringUtils.gd # 字符串工具 +│ ├── FileUtils.gd # 文件工具 +│ ├── TimeUtils.gd # 时间工具 +│ └── DebugUtils.gd # 调试工具 +├── components/ # 通用组件 +│ ├── HealthComponent.gd # 生命值组件 +│ ├── MovementComponent.gd # 移动组件 +│ ├── AnimationComponent.gd # 动画组件 +│ └── CollisionComponent.gd # 碰撞组件 +└── interfaces/ # 接口定义 + ├── IInteractable.gd # 可交互接口 + ├── IDamageable.gd # 可受伤接口 + ├── ICollectable.gd # 可收集接口 + └── ISaveable.gd # 可存储接口 +``` + +### 2.2 核心系统职责 + +#### 管理器 (Managers) +- **单例模式**:全局唯一实例 +- **生命周期管理**:负责系统初始化和清理 +- **状态维护**:维护全局状态信息 +- **服务提供**:为其他模块提供服务 + +#### 系统组件 (Systems) +- **功能封装**:封装特定功能逻辑 +- **可插拔设计**:可以独立启用或禁用 +- **事件驱动**:通过事件系统通信 +- **性能优化**:提供高效的实现方案 +## 3. 模块层 (module/) + +模块层包含可复用的功能模块,这些模块可以在不同场景中重复使用。 + +### 3.1 模块分类 + +``` +module/ +├── UI/ # UI模块 +│ ├── components/ # UI组件 +│ │ ├── Button/ # 按钮组件 +│ │ │ ├── CustomButton.gd +│ │ │ └── custom_button.tscn +│ │ ├── Dialog/ # 对话框组件 +│ │ │ ├── DialogBox.gd +│ │ │ └── dialog_box.tscn +│ │ ├── ProgressBar/ # 进度条组件 +│ │ │ ├── CustomProgressBar.gd +│ │ │ └── custom_progress_bar.tscn +│ │ └── InputField/ # 输入框组件 +│ │ ├── CustomInputField.gd +│ │ └── custom_input_field.tscn +│ ├── layouts/ # 布局组件 +│ │ ├── GridLayout.gd +│ │ ├── FlexLayout.gd +│ │ └── ResponsiveLayout.gd +│ └── animations/ # UI动画 +│ ├── FadeTransition.gd +│ ├── SlideTransition.gd +│ └── ScaleTransition.gd +├── Character/ # 角色模块 +│ ├── Player/ # 玩家角色 +│ │ ├── PlayerController.gd +│ │ ├── PlayerStats.gd +│ │ └── PlayerAnimator.gd +│ ├── NPC/ # NPC角色 +│ │ ├── NPCController.gd +│ │ ├── NPCDialogue.gd +│ │ └── NPCBehavior.gd +│ └── Enemy/ # 敌人角色 +│ ├── EnemyAI.gd +│ ├── EnemyStats.gd +│ └── EnemyBehavior.gd +├── Inventory/ # 背包模块 +│ ├── InventorySystem.gd +│ ├── Item.gd +│ ├── ItemSlot.gd +│ └── ItemDatabase.gd +├── Combat/ # 战斗模块 +│ ├── CombatSystem.gd +│ ├── Weapon.gd +│ ├── Skill.gd +│ └── DamageCalculator.gd +└── Dialogue/ # 对话模块 + ├── DialogueSystem.gd + ├── DialogueNode.gd + ├── DialogueParser.gd + └── DialogueUI.gd +``` + +### 3.2 模块设计原则 + +- **高内聚**:模块内部功能紧密相关 +- **低耦合**:模块间依赖最小化 +- **可配置**:通过配置文件自定义行为 +- **可扩展**:支持功能扩展和定制 +## 4. 资源层 (assets/) + +资源层统一管理所有静态资源文件,采用分类存储和标准化命名。 + +### 4.1 资源目录结构 + +``` +assets/ +├── sprites/ # 精灵图资源 +│ ├── characters/ # 角色精灵 +│ │ ├── player/ +│ │ │ ├── sprite_player_idle.png +│ │ │ ├── sprite_player_walk.png +│ │ │ └── sprite_player_attack.png +│ │ ├── enemies/ +│ │ │ ├── sprite_enemy_goblin_idle.png +│ │ │ └── sprite_enemy_orc_walk.png +│ │ └── npcs/ +│ │ ├── sprite_npc_merchant.png +│ │ └── sprite_npc_guard.png +│ ├── ui/ # UI精灵 +│ │ ├── buttons/ +│ │ │ ├── ui_button_normal.png +│ │ │ ├── ui_button_hover.png +│ │ │ └── ui_button_pressed.png +│ │ ├── icons/ +│ │ │ ├── icon_sword.png +│ │ │ ├── icon_shield.png +│ │ │ └── icon_potion.png +│ │ └── panels/ +│ │ ├── ui_panel_main.png +│ │ └── ui_panel_dialog.png +│ ├── environment/ # 环境精灵 +│ │ ├── backgrounds/ +│ │ │ ├── bg_forest.png +│ │ │ └── bg_dungeon.png +│ │ ├── tiles/ +│ │ │ ├── tile_grass_01.png +│ │ │ └── tile_stone_01.png +│ │ └── objects/ +│ │ ├── obj_tree.png +│ │ └── obj_rock.png +│ └── effects/ # 特效精灵 +│ ├── fx_explosion.png +│ ├── fx_magic_circle.png +│ └── fx_damage_numbers.png +├── audio/ # 音频资源 +│ ├── music/ # 背景音乐 +│ │ ├── music_main_menu.ogg +│ │ ├── music_battle.ogg +│ │ └── music_peaceful.ogg +│ ├── sounds/ # 音效 +│ │ ├── ui/ +│ │ │ ├── sound_button_click.wav +│ │ │ └── sound_menu_open.wav +│ │ ├── combat/ +│ │ │ ├── sound_sword_hit.wav +│ │ │ └── sound_explosion.wav +│ │ └── ambient/ +│ │ ├── sound_footsteps.wav +│ │ └── sound_wind.wav +│ └── voice/ # 语音 +│ ├── voice_npc_greeting.wav +│ └── voice_player_hurt.wav +├── fonts/ # 字体资源 +│ ├── font_main.ttf # 主要字体 +│ ├── font_title.ttf # 标题字体 +│ └── font_ui.ttf # UI字体 +├── materials/ # 材质资源 +│ ├── material_metal.tres +│ ├── material_wood.tres +│ └── material_water.tres +└── shaders/ # 着色器资源 + ├── shader_water.gdshader + ├── shader_fire.gdshader + └── shader_outline.gdshader +``` + +### 4.2 资源命名规范 + +#### 图片资源命名 +- **精灵图**:`sprite_[类别]_[名称]_[状态].png` + - 示例:`sprite_player_idle.png`、`sprite_enemy_goblin_walk.png` +- **UI图片**:`ui_[类型]_[名称]_[状态].png` + - 示例:`ui_button_normal.png`、`ui_panel_main.png` +- **图标**:`icon_[名称].png` + - 示例:`icon_sword.png`、`icon_health.png` +- **背景**:`bg_[场景名称].png` + - 示例:`bg_forest.png`、`bg_dungeon.png` +- **瓦片**:`tile_[材质]_[编号].png` + - 示例:`tile_grass_01.png`、`tile_stone_02.png` + +#### 音频资源命名 +- **音乐**:`music_[场景/情境].ogg` + - 示例:`music_battle.ogg`、`music_peaceful.ogg` +- **音效**:`sound_[动作/事件].wav` + - 示例:`sound_jump.wav`、`sound_explosion.wav` +- **语音**:`voice_[角色]_[内容].wav` + - 示例:`voice_npc_greeting.wav`、`voice_player_hurt.wav` + +#### 其他资源命名 +- **字体**:`font_[用途].ttf` + - 示例:`font_main.ttf`、`font_title.ttf` +- **材质**:`material_[材质名].tres` + - 示例:`material_metal.tres`、`material_wood.tres` +- **着色器**:`shader_[效果名].gdshader` + - 示例:`shader_water.gdshader`、`shader_fire.gdshader` +## 5. 脚本层 (scripts/) + +脚本层包含所有业务逻辑代码,按功能模块组织。 + +### 5.1 脚本目录结构 + +``` +scripts/ +├── scenes/ # 场景脚本 +│ ├── MainScene.gd # 主场景脚本 +│ ├── AuthScene.gd # 认证场景脚本 +│ ├── GameScene.gd # 游戏场景脚本 +│ └── BattleScene.gd # 战斗场景脚本 +├── ui/ # UI脚本 +│ ├── MainMenu.gd # 主菜单脚本 +│ ├── SettingsPanel.gd # 设置面板脚本 +│ ├── InventoryUI.gd # 背包界面脚本 +│ └── DialogueUI.gd # 对话界面脚本 +├── characters/ # 角色脚本 +│ ├── PlayerController.gd # 玩家控制器 +│ ├── EnemyAI.gd # 敌人AI +│ └── NPCBehavior.gd # NPC行为 +├── gameplay/ # 游戏玩法脚本 +│ ├── CombatSystem.gd # 战斗系统 +│ ├── QuestSystem.gd # 任务系统 +│ ├── InventorySystem.gd # 背包系统 +│ └── DialogueSystem.gd # 对话系统 +├── network/ # 网络脚本 +│ ├── NetworkClient.gd # 网络客户端 +│ ├── NetworkServer.gd # 网络服务器 +│ └── NetworkProtocol.gd # 网络协议 +└── data/ # 数据脚本 + ├── GameData.gd # 游戏数据 + ├── PlayerData.gd # 玩家数据 + ├── ItemData.gd # 物品数据 + └── ConfigData.gd # 配置数据 +``` + +## 6. 数据层 (data/) + +数据层存储游戏配置、关卡数据和其他静态数据文件。 + +### 6.1 数据目录结构 + +``` +data/ +├── configs/ # 配置文件 +│ ├── game_config.json # 游戏配置 +│ ├── audio_config.json # 音频配置 +│ ├── input_config.json # 输入配置 +│ └── graphics_config.json # 图形配置 +├── levels/ # 关卡数据 +│ ├── level_01.json # 第一关数据 +│ ├── level_02.json # 第二关数据 +│ └── level_boss.json # Boss关数据 +├── items/ # 物品数据 +│ ├── weapons.json # 武器数据 +│ ├── armor.json # 装备数据 +│ └── consumables.json # 消耗品数据 +├── characters/ # 角色数据 +│ ├── player_stats.json # 玩家属性 +│ ├── enemy_stats.json # 敌人属性 +│ └── npc_data.json # NPC数据 +├── dialogues/ # 对话数据 +│ ├── main_story.json # 主线对话 +│ ├── side_quests.json # 支线对话 +│ └── npc_dialogues.json # NPC对话 +└── localization/ # 本地化数据 + ├── en.json # 英文文本 + ├── zh_CN.json # 简体中文文本 + └── zh_TW.json # 繁体中文文本 +``` + +## 7. 测试层 (tests/) + +测试层包含单元测试、集成测试和功能测试。 + +### 7.1 测试目录结构 + +``` +tests/ +├── unit/ # 单元测试 +│ ├── test_player_controller.gd +│ ├── test_inventory_system.gd +│ └── test_combat_system.gd +├── integration/ # 集成测试 +│ ├── test_scene_transitions.gd +│ ├── test_save_load.gd +│ └── test_network_sync.gd +├── ui/ # UI测试 +│ ├── test_main_menu.gd +│ ├── test_inventory_ui.gd +│ └── test_dialogue_ui.gd +└── performance/ # 性能测试 + ├── test_memory_usage.gd + ├── test_frame_rate.gd + └── test_loading_times.gd +``` +## 8. 场景间通信机制 + +### 8.1 事件系统 + +使用全局事件系统实现场景间的松耦合通信: + +```gdscript +# 事件定义示例 +signal player_health_changed(new_health: int) +signal scene_transition_requested(scene_name: String) +signal item_collected(item_id: String) +signal quest_completed(quest_id: String) + +# 事件发送 +EventSystem.emit_signal("player_health_changed", 80) + +# 事件监听 +EventSystem.connect("player_health_changed", _on_player_health_changed) +``` + +### 8.2 管理器模式 + +通过单例管理器实现全局状态管理: + +```gdscript +# 场景切换 +SceneManager.change_scene("battle_scene") + +# 音频播放 +AudioManager.play_sound("sound_button_click") + +# 数据保存 +SaveManager.save_game_data(player_data) +``` + +## 9. 开发工作流 + +### 9.1 新场景开发流程 + +1. **创建场景文件**:在 `scenes/` 目录创建 `.tscn` 文件 +2. **编写场景脚本**:在 `scripts/scenes/` 创建对应脚本 +3. **添加UI组件**:使用 `module/UI/` 中的可复用组件 +4. **配置场景数据**:在 `data/` 目录添加相关配置 +5. **编写测试用例**:在 `tests/` 目录添加测试 +6. **更新文档**:更新相关文档说明 + +### 9.2 新功能模块开发流程 + +1. **设计模块接口**:定义模块的公共接口 +2. **实现核心逻辑**:在 `module/` 目录实现功能 +3. **添加管理器支持**:在 `core/managers/` 添加管理器 +4. **创建测试场景**:创建独立的测试场景 +5. **集成到主项目**:将模块集成到现有场景 +6. **性能优化**:进行性能测试和优化 + +## 10. 最佳实践 + +### 10.1 代码组织 + +- **单一职责**:每个类只负责一个功能 +- **依赖注入**:通过构造函数或属性注入依赖 +- **接口隔离**:使用接口定义模块间的契约 +- **配置外置**:将配置信息放在数据文件中 + +### 10.2 性能优化 + +- **对象池**:复用频繁创建的对象 +- **延迟加载**:按需加载资源和场景 +- **批量处理**:合并相似的操作 +- **内存管理**:及时释放不需要的资源 + +### 10.3 调试和测试 + +- **单元测试**:为核心逻辑编写单元测试 +- **集成测试**:测试模块间的交互 +- **性能监控**:监控内存和CPU使用情况 +- **日志记录**:记录关键操作和错误信息 + +## 11. 扩展指南 + +### 11.1 添加新场景 + +1. 在 `scenes/` 目录创建场景文件 +2. 在 `scripts/scenes/` 创建场景脚本 +3. 在 `SceneManager` 中注册新场景 +4. 添加场景切换逻辑 + +### 11.2 添加新模块 + +1. 在 `module/` 目录创建模块文件夹 +2. 实现模块的核心功能 +3. 创建模块管理器(如需要) +4. 编写模块文档和示例 + +### 11.3 添加新资源类型 + +1. 在 `assets/` 目录创建对应分类 +2. 更新命名规范文档 +3. 在资源加载器中添加支持 +4. 更新导入设置 + +--- + +## 总结 + +这个项目结构设计遵循了模块化、可扩展、易维护的原则。通过清晰的分层架构和标准化的命名规范,确保了项目的可读性和可维护性。每个开发者都应该遵循这个结构进行开发,以保持项目的一致性和质量。 + +如有任何疑问或建议,请参考相关文档或联系项目维护者。 \ No newline at end of file diff --git a/project.godot b/project.godot index 5645744..51655e5 100644 --- a/project.godot +++ b/project.godot @@ -11,5 +11,20 @@ config_version=5 [application] config/name="whaleTown" +run/main_scene="res://scenes/main_scene.tscn" config/features=PackedStringArray("4.5", "Forward Plus") config/icon="res://icon.svg" + +[autoload] + +GameManager="*res://core/managers/GameManager.gd" +SceneManager="*res://core/managers/SceneManager.gd" +EventSystem="*res://core/systems/EventSystem.gd" + +[display] + +window/size/viewport_width=1376 +window/size/viewport_height=768 +window/size/mode=2 +window/stretch/mode="canvas_items" +window/stretch/aspect="expand" diff --git a/scenes/main_scene.tscn b/scenes/main_scene.tscn index a525467..e08e7d2 100644 --- a/scenes/main_scene.tscn +++ b/scenes/main_scene.tscn @@ -1,8 +1,188 @@ -[gd_scene load_steps=2 format=3 uid="uid://4ptgx76y83mx"] +[gd_scene load_steps=4 format=3 uid="uid://4ptgx76y83mx"] -[sub_resource type="AudioStream" id="AudioStream_o3jxj"] +[ext_resource type="Texture2D" uid="uid://bx17oy8lvaca4" path="res://assets/ui/auth/bg_auth_scene.png" id="1_background"] +[ext_resource type="PackedScene" uid="uid://by7m8snb4xllf" path="res://scenes/auth_scene.tscn" id="2_main"] +[ext_resource type="Script" uid="uid://cejrxy23ldhug" path="res://scripts/scenes/MainScene.gd" id="3_script"] -[node name="Node2D" type="Node2D"] +[node name="Main" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("3_script") -[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] -stream = SubResource("AudioStream_o3jxj") +[node name="BackgroundImage" type="TextureRect" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("1_background") +expand_mode = 1 +stretch_mode = 6 + +[node name="AuthScene" parent="." instance=ExtResource("2_main")] +layout_mode = 1 + +[node name="MainGameUI" type="Control" parent="."] +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="UIOverlay" type="ColorRect" parent="MainGameUI"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 0, 0, 0.3) + +[node name="TopBar" type="Panel" parent="MainGameUI"] +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 60.0 +grow_horizontal = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="MainGameUI/TopBar"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 20.0 +offset_top = 10.0 +offset_right = -20.0 +offset_bottom = -10.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="WelcomeLabel" type="Label" parent="MainGameUI/TopBar/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_colors/font_color = Color(1, 1, 1, 1) +text = "🐋 欢迎来到鲸鱼镇!" +vertical_alignment = 1 + +[node name="UserLabel" type="Label" parent="MainGameUI/TopBar/HBoxContainer"] +layout_mode = 2 +theme_override_colors/font_color = Color(1, 1, 1, 1) +text = "当前用户: [用户名]" +horizontal_alignment = 2 +vertical_alignment = 1 + +[node name="LogoutButton" type="Button" parent="MainGameUI/TopBar/HBoxContainer"] +layout_mode = 2 +text = "退出" + +[node name="MainContent" type="Control" parent="MainGameUI"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = 60.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="CenterContainer" type="CenterContainer" parent="MainGameUI/MainContent"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="MainGameUI/MainContent/CenterContainer"] +custom_minimum_size = Vector2(600, 400) +layout_mode = 2 + +[node name="GameTitle" type="Label" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer"] +layout_mode = 2 +theme_override_colors/font_color = Color(1, 1, 1, 1) +theme_override_font_sizes/font_size = 24 +text = "🏘️ 鲸鱼镇主界面" +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer"] +layout_mode = 2 + +[node name="GameMenuGrid" type="GridContainer" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +columns = 2 + +[node name="ExploreButton" type="Button" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/GameMenuGrid"] +custom_minimum_size = Vector2(280, 80) +layout_mode = 2 +text = "🗺️ 探索小镇" + +[node name="InventoryButton" type="Button" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/GameMenuGrid"] +custom_minimum_size = Vector2(280, 80) +layout_mode = 2 +text = "🎒 背包物品" + +[node name="ShopButton" type="Button" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/GameMenuGrid"] +custom_minimum_size = Vector2(280, 80) +layout_mode = 2 +text = "🏪 商店购物" + +[node name="FriendsButton" type="Button" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/GameMenuGrid"] +custom_minimum_size = Vector2(280, 80) +layout_mode = 2 +text = "👥 好友列表" + +[node name="HSeparator2" type="HSeparator" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer"] +layout_mode = 2 + +[node name="StatusPanel" type="Panel" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(0, 120) +layout_mode = 2 + +[node name="StatusContainer" type="VBoxContainer" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/StatusPanel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 20.0 +offset_top = 10.0 +offset_right = -20.0 +offset_bottom = -10.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="StatusTitle" type="Label" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/StatusPanel/StatusContainer"] +layout_mode = 2 +theme_override_colors/font_color = Color(1, 1, 1, 1) +text = "📊 玩家状态" +horizontal_alignment = 1 + +[node name="StatusGrid" type="GridContainer" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/StatusPanel/StatusContainer"] +layout_mode = 2 +columns = 2 + +[node name="LevelLabel" type="Label" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/StatusPanel/StatusContainer/StatusGrid"] +layout_mode = 2 +theme_override_colors/font_color = Color(1, 1, 1, 1) +text = "等级: 1" + +[node name="CoinsLabel" type="Label" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/StatusPanel/StatusContainer/StatusGrid"] +layout_mode = 2 +theme_override_colors/font_color = Color(1, 1, 1, 1) +text = "金币: 100" + +[node name="ExpLabel" type="Label" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/StatusPanel/StatusContainer/StatusGrid"] +layout_mode = 2 +theme_override_colors/font_color = Color(1, 1, 1, 1) +text = "经验: 0/100" + +[node name="EnergyLabel" type="Label" parent="MainGameUI/MainContent/CenterContainer/VBoxContainer/StatusPanel/StatusContainer/StatusGrid"] +layout_mode = 2 +theme_override_colors/font_color = Color(1, 1, 1, 1) +text = "体力: 100/100"