docs: 重新组织文档结构,按开发阶段分类

新的目录结构:
  01-项目入门/     # 新人必读,项目基础
  02-开发规范/     # 编码标准和规范
  03-技术实现/     # 具体开发指导
  04-高级开发/     # 进阶开发技巧
  05-部署运维/     # 发布和部署
  06-功能模块/     # 特定功能文档

 新增导航文档:
- docs/README.md - 完整的文档导航和使用指南
- 各目录下的README.md - 分类说明和使用指导

 优化效果:
- 开发者可以按阶段快速定位需要的文档
- 新人有清晰的学习路径
- 不同角色有针对性的文档推荐
- 提供了问题导向的快速查找功能
This commit is contained in:
2025-12-31 18:02:16 +08:00
parent 2998fd2d11
commit 1ff677b3b2
22 changed files with 449 additions and 0 deletions

View File

@@ -0,0 +1,963 @@
# Pixel Game Server API 文档
**版本**: 1.1.1
**更新时间**: 2025-12-25
## 🚨 后端对前端的提示与注意点
### 重要提醒
1. **邮箱冲突检测**: 发送邮箱验证码前会检查邮箱是否已被注册已注册邮箱返回409状态码
2. **HTTP状态码**: 所有接口根据业务结果返回正确状态码409冲突、400参数错误、401认证失败等
3. **验证码有效期**: 所有验证码有效期为5分钟
4. **频率限制**: 验证码发送限制1次/分钟注册限制10次/5分钟
5. **测试模式**: 开发环境下邮件服务返回206状态码验证码在响应中返回
6. **冷却时间自动清除**: 注册、密码重置、验证码登录成功后会自动清除验证码冷却时间,方便后续操作
### 错误处理规范
- **409 Conflict**: 资源冲突(用户名、邮箱已存在)
- **400 Bad Request**: 参数错误、验证码错误
- **401 Unauthorized**: 认证失败、密码错误
- **429 Too Many Requests**: 频率限制
- **206 Partial Content**: 测试模式(验证码未真实发送)
### 前端开发建议
1. 根据HTTP状态码进行错误处理不要只依赖success字段
2. 邮箱注册流程:先发送验证码 → 检查409冲突 → 使用验证码注册
3. 测试模式下验证码在响应中返回,生产环境需用户查收邮件
4. 实现重试机制处理429频率限制错误
5. 注册/重置密码成功后,验证码冷却时间会自动清除,可立即发送新验证码
---
## 📋 API接口列表
### 应用状态接口
- `GET /` - 获取应用状态
### 用户认证接口
- `POST /auth/login` - 用户登录
- `POST /auth/register` - 用户注册
- `POST /auth/github` - GitHub OAuth登录
- `POST /auth/verification-code-login` - 验证码登录
- `POST /auth/send-login-verification-code` - 发送登录验证码
- `POST /auth/forgot-password` - 发送密码重置验证码
- `POST /auth/reset-password` - 重置密码
- `PUT /auth/change-password` - 修改密码
- `POST /auth/send-email-verification` - 发送邮箱验证码
- `POST /auth/verify-email` - 验证邮箱验证码
- `POST /auth/resend-email-verification` - 重新发送邮箱验证码
### 管理员接口
- `POST /admin/auth/login` - 管理员登录
- `GET /admin/users` - 获取用户列表
- `GET /admin/users/:id` - 获取用户详情
- `POST /admin/users/:id/reset-password` - 管理员重置用户密码
- `GET /admin/logs/runtime` - 获取运行时日志
- `GET /admin/logs/archive` - 获取归档日志
### 用户管理接口
- `PUT /admin/users/:id/status` - 修改用户状态
- `POST /admin/users/batch-status` - 批量修改用户状态
- `GET /admin/users/status-stats` - 获取用户状态统计
---
## 🧪 API接口详细说明与测试用例
### 1. 获取应用状态
**接口**: `GET /`
#### 成功响应 (200)
```json
{
"service": "Pixel Game Server",
"version": "1.1.1",
"status": "running",
"timestamp": "2025-12-25T10:27:44.352Z",
"uptime": 8,
"environment": "development",
"storage_mode": "database"
}
```
---
### 2. 用户登录
**接口**: `POST /auth/login`
#### 请求体
```json
{
"identifier": "testuser",
"password": "password123"
}
```
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"user": {
"id": "1",
"username": "testuser",
"nickname": "测试用户",
"email": "test@example.com",
"phone": null,
"avatar_url": null,
"role": 1,
"created_at": "2025-12-17T10:00:00.000Z"
},
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"is_new_user": false,
"message": "登录成功"
},
"message": "登录成功"
}
```
#### 认证失败响应 (401)
```json
{
"success": false,
"message": "用户名、邮箱或手机号不存在",
"error_code": "LOGIN_FAILED"
}
```
#### 密码错误响应 (401)
```json
{
"success": false,
"message": "密码错误",
"error_code": "LOGIN_FAILED"
}
```
---
### 3. 用户注册
**接口**: `POST /auth/register`
#### 请求体(无邮箱)
```json
{
"username": "newuser",
"password": "password123",
"nickname": "新用户"
}
```
#### 请求体(带邮箱验证)
```json
{
"username": "newuser",
"password": "password123",
"nickname": "新用户",
"email": "newuser@example.com",
"email_verification_code": "123456"
}
```
#### 成功响应 (201)
```json
{
"success": true,
"data": {
"user": {
"id": "2",
"username": "newuser",
"nickname": "新用户",
"email": "newuser@example.com",
"phone": null,
"avatar_url": null,
"role": 1,
"created_at": "2025-12-17T10:00:00.000Z"
},
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"is_new_user": true,
"message": "注册成功"
},
"message": "注册成功"
}
```
#### 用户名冲突响应 (409)
```json
{
"success": false,
"message": "用户名已存在",
"error_code": "REGISTER_FAILED"
}
```
#### 邮箱冲突响应 (409)
```json
{
"success": false,
"message": "邮箱已存在",
"error_code": "REGISTER_FAILED"
}
```
#### 验证码错误响应 (400)
```json
{
"success": false,
"message": "验证码不存在或已过期",
"error_code": "REGISTER_FAILED"
}
```
---
### 4. 发送邮箱验证码
**接口**: `POST /auth/send-email-verification`
#### 请求体
```json
{
"email": "test@example.com"
}
```
#### 成功响应 (200) - 生产环境
```json
{
"success": true,
"data": {
"is_test_mode": false
},
"message": "验证码已发送,请查收邮件"
}
```
#### 测试模式响应 (206) - 开发环境
```json
{
"success": false,
"data": {
"verification_code": "123456",
"is_test_mode": true
},
"message": "⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。",
"error_code": "TEST_MODE_ONLY"
}
```
#### 邮箱冲突响应 (409)
```json
{
"success": false,
"message": "邮箱已被注册,请使用其他邮箱或直接登录",
"error_code": "SEND_EMAIL_VERIFICATION_FAILED"
}
```
#### 频率限制响应 (429)
```json
{
"success": false,
"message": "验证码发送过于频繁请1分钟后再试",
"error_code": "TOO_MANY_REQUESTS",
"throttle_info": {
"limit": 1,
"window_seconds": 60,
"current_requests": 1,
"reset_time": "2025-12-25T10:07:37.056Z"
}
}
```
---
### 5. 验证码登录
**接口**: `POST /auth/verification-code-login`
#### 请求体
```json
{
"identifier": "test@example.com",
"verification_code": "123456"
}
```
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"user": {
"id": "1",
"username": "testuser",
"nickname": "测试用户",
"email": "test@example.com",
"phone": null,
"avatar_url": null,
"role": 1,
"created_at": "2025-12-17T10:00:00.000Z"
},
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"is_new_user": false,
"message": "验证码登录成功"
},
"message": "验证码登录成功"
}
```
#### 验证码错误响应 (401)
```json
{
"success": false,
"message": "验证码验证失败",
"error_code": "VERIFICATION_CODE_LOGIN_FAILED"
}
```
#### 用户不存在响应 (404)
```json
{
"success": false,
"message": "用户不存在,请先注册账户",
"error_code": "VERIFICATION_CODE_LOGIN_FAILED"
}
```
---
### 6. 发送登录验证码
**接口**: `POST /auth/send-login-verification-code`
#### 请求体
```json
{
"identifier": "test@example.com"
}
```
#### 成功响应 (200) - 生产环境
```json
{
"success": true,
"data": {
"is_test_mode": false
},
"message": "验证码已发送,请查收"
}
```
#### 测试模式响应 (206) - 开发环境
```json
{
"success": false,
"data": {
"verification_code": "654321",
"is_test_mode": true
},
"message": "⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。",
"error_code": "TEST_MODE_ONLY"
}
```
#### 用户不存在响应 (404)
```json
{
"success": false,
"message": "用户不存在",
"error_code": "SEND_LOGIN_CODE_FAILED"
}
```
---
### 7. 发送密码重置验证码
**接口**: `POST /auth/forgot-password`
#### 请求体
```json
{
"identifier": "test@example.com"
}
```
#### 成功响应 (200) - 生产环境
```json
{
"success": true,
"data": {
"is_test_mode": false
},
"message": "验证码已发送,请查收"
}
```
#### 测试模式响应 (206) - 开发环境
```json
{
"success": false,
"data": {
"verification_code": "789012",
"is_test_mode": true
},
"message": "⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。",
"error_code": "TEST_MODE_ONLY"
}
```
#### 用户不存在响应 (404)
```json
{
"success": false,
"message": "用户不存在",
"error_code": "SEND_CODE_FAILED"
}
```
---
### 8. 重置密码
**接口**: `POST /auth/reset-password`
#### 请求体
```json
{
"identifier": "test@example.com",
"verification_code": "789012",
"new_password": "newpassword123"
}
```
#### 成功响应 (200)
```json
{
"success": true,
"message": "密码重置成功"
}
```
#### 验证码错误响应 (400)
```json
{
"success": false,
"message": "验证码验证失败",
"error_code": "RESET_PASSWORD_FAILED"
}
```
---
### 9. 修改密码
**接口**: `PUT /auth/change-password`
#### 请求体
```json
{
"user_id": "1",
"old_password": "oldpassword123",
"new_password": "newpassword123"
}
```
#### 成功响应 (200)
```json
{
"success": true,
"message": "密码修改成功"
}
```
#### 旧密码错误响应 (401)
```json
{
"success": false,
"message": "旧密码错误",
"error_code": "CHANGE_PASSWORD_FAILED"
}
```
---
### 10. GitHub OAuth登录
**接口**: `POST /auth/github`
#### 请求体
```json
{
"github_id": "12345678",
"username": "octocat",
"nickname": "The Octocat",
"email": "octocat@github.com",
"avatar_url": "https://github.com/images/error/octocat_happy.gif"
}
```
#### 成功响应 (200) - 已存在用户
```json
{
"success": true,
"data": {
"user": {
"id": "3",
"username": "octocat",
"nickname": "The Octocat",
"email": "octocat@github.com",
"phone": null,
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"role": 1,
"created_at": "2025-12-17T10:00:00.000Z"
},
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"is_new_user": false,
"message": "GitHub登录成功"
},
"message": "GitHub登录成功"
}
```
#### 成功响应 (200) - 新用户注册
```json
{
"success": true,
"data": {
"user": {
"id": "4",
"username": "octocat_1",
"nickname": "The Octocat",
"email": "octocat@github.com",
"phone": null,
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"role": 1,
"created_at": "2025-12-17T10:00:00.000Z"
},
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"is_new_user": true,
"message": "GitHub账户绑定成功"
},
"message": "GitHub账户绑定成功"
}
```
---
### 11. 验证邮箱验证码
**接口**: `POST /auth/verify-email`
#### 请求体
```json
{
"email": "test@example.com",
"verification_code": "123456"
}
```
#### 成功响应 (200)
```json
{
"success": true,
"message": "邮箱验证成功"
}
```
#### 验证码错误响应 (400)
```json
{
"success": false,
"message": "验证码错误",
"error_code": "EMAIL_VERIFICATION_FAILED"
}
```
---
### 12. 重新发送邮箱验证码
**接口**: `POST /auth/resend-email-verification`
#### 请求体
```json
{
"email": "test@example.com"
}
```
#### 成功响应 (200) - 生产环境
```json
{
"success": true,
"data": {
"is_test_mode": false
},
"message": "验证码已重新发送,请查收邮件"
}
```
#### 测试模式响应 (206) - 开发环境
```json
{
"success": false,
"data": {
"verification_code": "456789",
"is_test_mode": true
},
"message": "⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。",
"error_code": "TEST_MODE_ONLY"
}
```
#### 邮箱已验证响应 (400)
```json
{
"success": false,
"message": "邮箱已验证,无需重复验证",
"error_code": "RESEND_EMAIL_VERIFICATION_FAILED"
}
```
---
### 13. 管理员登录
**接口**: `POST /admin/auth/login`
#### 请求体
```json
{
"username": "admin",
"password": "Admin123456"
}
```
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"admin": {
"id": "1",
"username": "admin",
"nickname": "管理员",
"role": 0
},
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 28800,
"message": "管理员登录成功"
},
"message": "管理员登录成功"
}
```
#### 认证失败响应 (401)
```json
{
"success": false,
"message": "用户名或密码错误",
"error_code": "ADMIN_LOGIN_FAILED"
}
```
#### 权限不足响应 (403)
```json
{
"success": false,
"message": "权限不足,需要管理员权限",
"error_code": "ADMIN_LOGIN_FAILED"
}
```
---
### 14. 获取用户列表
**接口**: `GET /admin/users`
#### 查询参数
- `page`: 页码可选默认1
- `limit`: 每页数量可选默认10
- `status`: 用户状态筛选(可选)
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"users": [
{
"id": "1",
"username": "testuser",
"nickname": "测试用户",
"email": "test@example.com",
"phone": null,
"role": 1,
"status": "active",
"email_verified": true,
"created_at": "2025-12-17T10:00:00.000Z",
"updated_at": "2025-12-17T10:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 1,
"pages": 1
}
},
"message": "用户列表获取成功"
}
```
---
### 15. 获取用户详情
**接口**: `GET /admin/users/:id`
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"user": {
"id": "1",
"username": "testuser",
"nickname": "测试用户",
"email": "test@example.com",
"phone": null,
"role": 1,
"status": "active",
"email_verified": true,
"github_id": null,
"avatar_url": null,
"created_at": "2025-12-17T10:00:00.000Z",
"updated_at": "2025-12-17T10:00:00.000Z"
}
},
"message": "用户详情获取成功"
}
```
#### 用户不存在响应 (404)
```json
{
"success": false,
"message": "用户不存在",
"error_code": "USER_NOT_FOUND"
}
```
---
### 16. 管理员重置用户密码
**接口**: `POST /admin/users/:id/reset-password`
#### 请求体
```json
{
"new_password": "newpassword123"
}
```
#### 成功响应 (200)
```json
{
"success": true,
"message": "用户密码重置成功"
}
```
#### 用户不存在响应 (404)
```json
{
"success": false,
"message": "用户不存在",
"error_code": "USER_NOT_FOUND"
}
```
---
### 17. 修改用户状态
**接口**: `PUT /admin/users/:id/status`
#### 请求体
```json
{
"status": "locked",
"reason": "违规操作"
}
```
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"user": {
"id": "1",
"username": "testuser",
"status": "locked",
"updated_at": "2025-12-17T10:00:00.000Z"
}
},
"message": "用户状态修改成功"
}
```
#### 状态值无效响应 (400)
```json
{
"success": false,
"message": "无效的用户状态值",
"error_code": "USER_STATUS_UPDATE_FAILED"
}
```
---
### 18. 批量修改用户状态
**接口**: `POST /admin/users/batch-status`
#### 请求体
```json
{
"user_ids": ["1", "2", "3"],
"status": "active",
"reason": "批量激活"
}
```
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"updated_count": 3,
"failed_count": 0,
"results": [
{
"user_id": "1",
"success": true,
"new_status": "active"
},
{
"user_id": "2",
"success": true,
"new_status": "active"
},
{
"user_id": "3",
"success": true,
"new_status": "active"
}
]
},
"message": "批量状态修改完成"
}
```
---
### 19. 获取用户状态统计
**接口**: `GET /admin/users/status-stats`
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"stats": {
"active": 15,
"inactive": 3,
"locked": 2,
"banned": 1,
"deleted": 0,
"pending": 5
},
"total": 26
},
"message": "用户状态统计获取成功"
}
```
---
### 20. 获取运行时日志
**接口**: `GET /admin/logs/runtime`
#### 查询参数
- `lines`: 日志行数可选默认100
- `level`: 日志级别(可选)
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"logs": [
"[2025-12-25 18:27:35] LOG [NestApplication] Nest application successfully started",
"[2025-12-25 18:27:35] LOG [RouterExplorer] Mapped {/, GET} route"
],
"total_lines": 2,
"timestamp": "2025-12-25T10:27:44.352Z"
},
"message": "运行时日志获取成功"
}
```
---
### 21. 获取归档日志
**接口**: `GET /admin/logs/archive`
#### 查询参数
- `date`: 日期YYYY-MM-DD格式可选
- `download`: 是否下载(可选)
#### 成功响应 (200)
```json
{
"success": true,
"data": {
"files": [
{
"filename": "app-2025-12-24.log",
"size": 1024,
"created_at": "2025-12-24T00:00:00.000Z"
}
],
"total_files": 1
},
"message": "归档日志列表获取成功"
}
```
---
## 📊 版本更新记录
### v1.1.2 (2025-12-25)
- **验证码冷却优化**: 注册、密码重置、验证码登录成功后自动清除验证码冷却时间
- **用户体验提升**: 成功操作后可立即发送新的验证码,无需等待冷却时间
- **代码健壮性**: 冷却时间清除失败不影响主要业务流程
### v1.1.1 (2025-12-25)
- **邮箱冲突检测优化**: 发送邮箱验证码前检查邮箱是否已被注册
- **用户体验提升**: 避免向已注册邮箱发送无用验证码
- **错误处理改进**: 返回409 Conflict状态码和明确错误信息
### v1.1.0 (2025-12-25)
- **新增验证码登录功能**: 支持邮箱验证码登录
- **HTTP状态码修复**: 所有接口返回正确的业务状态码
- **完善错误处理**: 统一错误响应格式和错误代码

View File

@@ -0,0 +1,120 @@
# 🔧 技术实现
> **适用人群**: 正在开发功能的程序员
> **使用时机**: 具体功能开发时
这个目录包含了具体的技术实现指导,帮助开发者快速实现各种游戏功能和系统集成。
## 📋 实现指南
### 核心实现 🎮
**[实现细节规范.md](实现细节规范.md)**
- 玩家角色实现标准
- NPC交互系统实现
- TileMap图层配置规范
- 交互物品实现模板
- 性能优化要求
### 网络集成 🌐
**[API接口文档.md](API接口文档.md)**
- 完整的后端API接口说明
- 请求格式和响应格式
- 错误码和处理方式
- 认证和权限管理
**[网络管理器设置.md](网络管理器设置.md)**
- NetworkManager配置方法
- 网络请求封装使用
- 错误处理机制
- 响应数据处理
### 质量保证 🧪
**[测试指南.md](测试指南.md)**
- API接口测试方法
- Python测试脚本使用
- Godot内置测试
- 测试用例编写
## 🎯 开发流程
### 功能开发标准流程
1. **需求分析** - 明确功能需求和技术方案
2. **架构设计** - 参考实现细节规范设计架构
3. **编码实现** - 按照规范编写代码
4. **接口集成** - 使用API文档进行后端集成
5. **功能测试** - 使用测试指南验证功能
6. **代码审查** - 检查规范遵循情况
### 常见开发场景
#### 🎮 实现新的游戏角色
1. 阅读 [实现细节规范.md](实现细节规范.md) 中的角色实现部分
2. 使用提供的代码模板创建角色
3. 配置相机和交互系统
4. 测试移动和交互功能
#### 🌐 集成新的API接口
1. 查看 [API接口文档.md](API接口文档.md) 了解接口规范
2. 使用 [网络管理器设置.md](网络管理器设置.md) 配置网络请求
3. 实现数据处理和错误处理
4. 使用 [测试指南.md](测试指南.md) 验证接口功能
#### 🗺️ 创建新的游戏场景
1. 参考 [实现细节规范.md](实现细节规范.md) 中的TileMap配置
2. 设置正确的图层结构和碰撞检测
3. 配置相机边界和Y排序
4. 添加交互物品和NPC
## 🔍 问题排查
### 常见问题类型
#### 网络相关问题
- **API调用失败** → 检查 [API接口文档.md](API接口文档.md) 中的接口格式
- **网络超时** → 参考 [网络管理器设置.md](网络管理器设置.md) 的超时配置
- **数据解析错误** → 查看响应格式和错误处理
#### 游戏对象问题
- **角色移动异常** → 检查 [实现细节规范.md](实现细节规范.md) 中的移动实现
- **交互不响应** → 验证InteractionArea配置和事件系统
- **相机边界错误** → 检查TileMap边界计算
#### 性能问题
- **帧率下降** → 参考性能优化要求
- **内存泄漏** → 检查资源管理和对象生命周期
### 调试技巧
1. **使用Godot调试器** - 设置断点调试代码逻辑
2. **查看控制台输出** - 关注错误和警告信息
3. **使用测试脚本** - 编写简单测试验证功能
4. **性能分析** - 使用Godot的性能分析工具
## 📚 参考资源
### 内部资源
- [02-开发规范](../02-开发规范/) - 编码规范和架构设计
- [04-高级开发](../04-高级开发/) - 进阶开发技巧
- [06-功能模块](../06-功能模块/) - 特定功能实现
### 外部资源
- [Godot官方文档](https://docs.godotengine.org/)
- [GDScript语言参考](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/)
- [Godot最佳实践](https://docs.godotengine.org/en/stable/tutorials/best_practices/)
## 💡 开发建议
### 效率提升
- 使用代码模板快速创建标准结构
- 善用Godot的场景实例化功能
- 合理使用@export变量进行配置
- 充分利用事件系统解耦组件
### 质量保证
- 每个功能都要编写对应测试
- 定期进行代码审查
- 关注性能指标和内存使用
- 保持代码简洁和可读性
---
**记住:好的实现不仅要功能正确,更要易于维护和扩展!**

View File

@@ -0,0 +1,388 @@
# 实现细节规范
本文档详细说明了WhaleTown项目中各种游戏对象的具体实现要求和技术细节。
## 🎮 玩家实现规范
### 基础要求
- **节点类型**: 必须使用 `CharacterBody2D`
- **移动系统**: 使用 `move_and_slide()` 方法
- **相机集成**: 必须包含 `Camera2D` 子节点
### 玩家节点结构
```
Player (CharacterBody2D)
├── Sprite2D # 玩家精灵
├── CollisionShape2D # 碰撞形状
├── Camera2D # 玩家相机
│ └── [相机配置]
├── InteractionArea (Area2D) # 交互检测区域
│ └── CollisionShape2D
└── AnimationPlayer # 动画播放器
```
### 相机配置要求
```gdscript
# Player.gd 中的相机设置
@onready var camera: Camera2D = $Camera2D
func _ready() -> void:
# 必须启用位置平滑
camera.position_smoothing_enabled = true
camera.position_smoothing_speed = 5.0
# 设置相机边界基于TileMap
_setup_camera_limits()
func _setup_camera_limits() -> void:
# 获取当前场景的TileMap
var tilemap = get_tree().get_first_node_in_group("tilemap")
if tilemap and tilemap is TileMap:
var used_rect = tilemap.get_used_rect()
var tile_size = tilemap.tile_set.tile_size
# 计算世界坐标边界
camera.limit_left = used_rect.position.x * tile_size.x
camera.limit_top = used_rect.position.y * tile_size.y
camera.limit_right = used_rect.end.x * tile_size.x
camera.limit_bottom = used_rect.end.y * tile_size.y
```
### 移动实现模板
```gdscript
extends CharacterBody2D
class_name Player
@export var move_speed: float = 200.0
@export var acceleration: float = 1000.0
@export var friction: float = 1000.0
@onready var sprite: Sprite2D = $Sprite2D
@onready var camera: Camera2D = $Camera2D
func _ready() -> void:
# 设置相机
camera.position_smoothing_enabled = true
_setup_camera_limits()
func _physics_process(delta: float) -> void:
_handle_movement(delta)
func _handle_movement(delta: float) -> void:
# 获取输入方向
var input_direction := Input.get_vector(
"move_left", "move_right",
"move_up", "move_down"
)
# 应用移动
if input_direction != Vector2.ZERO:
velocity = velocity.move_toward(input_direction * move_speed, acceleration * delta)
else:
velocity = velocity.move_toward(Vector2.ZERO, friction * delta)
move_and_slide()
# 发送移动事件
if velocity.length() > 0:
EventSystem.emit_event(EventNames.PLAYER_MOVED, {
"position": global_position,
"velocity": velocity
})
```
## 🤖 NPC实现规范
### 基础要求
- **节点类型**: 使用 `CharacterBody2D``StaticBody2D`
- **交互区域**: 必须包含名为 `InteractionArea``Area2D`
- **事件通信**: 通过 `EventSystem` 触发交互
### NPC节点结构
```
NPC (CharacterBody2D)
├── Sprite2D # NPC精灵
├── CollisionShape2D # 物理碰撞
├── InteractionArea (Area2D) # 交互检测区域
│ └── CollisionShape2D # 交互碰撞形状
├── DialogueComponent # 对话组件
└── AnimationPlayer # 动画播放器
```
### NPC实现模板
```gdscript
extends CharacterBody2D
class_name NPC
@export var npc_name: String = "NPC"
@export var dialogue_resource: DialogueResource
@onready var interaction_area: Area2D = $InteractionArea
@onready var sprite: Sprite2D = $Sprite2D
signal interaction_available(npc: NPC)
signal interaction_unavailable(npc: NPC)
func _ready() -> void:
# 连接交互区域信号
interaction_area.body_entered.connect(_on_interaction_area_entered)
interaction_area.body_exited.connect(_on_interaction_area_exited)
# 监听交互事件
EventSystem.connect_event(EventNames.INTERACT_PRESSED, _on_interact_pressed)
func _on_interaction_area_entered(body: Node2D) -> void:
if body.is_in_group("player"):
interaction_available.emit(self)
# 显示交互提示
_show_interaction_hint()
func _on_interaction_area_exited(body: Node2D) -> void:
if body.is_in_group("player"):
interaction_unavailable.emit(self)
# 隐藏交互提示
_hide_interaction_hint()
func _on_interact_pressed(data: Dictionary = {}) -> void:
# 检查玩家是否在交互范围内
if _is_player_in_range():
start_dialogue()
func start_dialogue() -> void:
EventSystem.emit_event(EventNames.NPC_TALKED, {
"npc": self,
"npc_name": npc_name,
"dialogue": dialogue_resource
})
func _is_player_in_range() -> bool:
var bodies = interaction_area.get_overlapping_bodies()
for body in bodies:
if body.is_in_group("player"):
return true
return false
```
## 🗺️ TileMap图层规范
### 图层配置要求
TileMap必须按以下标准配置图层
#### 图层0地面层 (Ground)
- **用途**: 地面纹理、道路、草地等
- **碰撞**: 禁用物理层
- **渲染**: 最底层渲染
- **Y排序**: 禁用
```gdscript
# 设置地面层
var ground_layer = tilemap.get_layer(0)
tilemap.set_layer_name(0, "Ground")
tilemap.set_layer_enabled(0, true)
tilemap.set_layer_y_sort_enabled(0, false)
# 不设置物理层
```
#### 图层1障碍层 (Obstacles)
- **用途**: 墙壁、树木、建筑等不可通过的障碍
- **碰撞**: 启用物理层
- **渲染**: 中间层
- **Y排序**: 禁用
```gdscript
# 设置障碍层
tilemap.set_layer_name(1, "Obstacles")
tilemap.set_layer_enabled(1, true)
tilemap.set_layer_y_sort_enabled(1, false)
# 设置物理层用于碰撞检测
tilemap.set_layer_physics_enabled(1, true)
```
#### 图层2装饰层 (Decoration)
- **用途**: 装饰物、前景元素
- **碰撞**: 根据需要设置
- **渲染**: 最上层
- **Y排序**: 启用(重要!)
```gdscript
# 设置装饰层
tilemap.set_layer_name(2, "Decoration")
tilemap.set_layer_enabled(2, true)
tilemap.set_layer_y_sort_enabled(2, true) # 启用Y排序
tilemap.set_layer_y_sort_origin(2, 16) # 设置排序原点
```
### TileMap设置模板
```gdscript
extends TileMap
class_name GameTileMap
func _ready() -> void:
# 设置TileMap为tilemap组
add_to_group("tilemap")
# 配置图层
_setup_layers()
# 通知相机系统更新边界
EventSystem.emit_event(EventNames.TILEMAP_READY, {
"tilemap": self,
"used_rect": get_used_rect()
})
func _setup_layers() -> void:
# 确保有足够的图层
while get_layers_count() < 3:
add_layer(-1)
# 配置地面层 (0)
set_layer_name(0, "Ground")
set_layer_y_sort_enabled(0, false)
# 配置障碍层 (1)
set_layer_name(1, "Obstacles")
set_layer_y_sort_enabled(1, false)
set_layer_physics_enabled(1, true)
# 配置装饰层 (2)
set_layer_name(2, "Decoration")
set_layer_y_sort_enabled(2, true)
set_layer_y_sort_origin(2, tile_set.tile_size.y / 2)
```
## 🎯 交互物实现规范
### 可收集物品
```gdscript
extends Area2D
class_name CollectibleItem
@export var item_name: String = "Item"
@export var item_value: int = 1
@onready var sprite: Sprite2D = $Sprite2D
@onready var collision: CollisionShape2D = $CollisionShape2D
func _ready() -> void:
body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("player"):
collect_item(body)
func collect_item(collector: Node2D) -> void:
# 发送收集事件
EventSystem.emit_event(EventNames.ITEM_COLLECTED, {
"item_name": item_name,
"item_value": item_value,
"collector": collector,
"position": global_position
})
# 播放收集动画
_play_collect_animation()
func _play_collect_animation() -> void:
var tween = create_tween()
tween.parallel().tween_property(self, "scale", Vector2.ZERO, 0.3)
tween.parallel().tween_property(self, "modulate:a", 0.0, 0.3)
await tween.finished
queue_free()
```
### 可交互对象
```gdscript
extends StaticBody2D
class_name InteractableObject
@export var interaction_text: String = "按E交互"
@export var can_interact: bool = true
@onready var interaction_area: Area2D = $InteractionArea
@onready var sprite: Sprite2D = $Sprite2D
var player_in_range: bool = false
func _ready() -> void:
interaction_area.body_entered.connect(_on_interaction_area_entered)
interaction_area.body_exited.connect(_on_interaction_area_exited)
EventSystem.connect_event(EventNames.INTERACT_PRESSED, _on_interact_pressed)
func _on_interaction_area_entered(body: Node2D) -> void:
if body.is_in_group("player") and can_interact:
player_in_range = true
_show_interaction_prompt()
func _on_interaction_area_exited(body: Node2D) -> void:
if body.is_in_group("player"):
player_in_range = false
_hide_interaction_prompt()
func _on_interact_pressed(data: Dictionary = {}) -> void:
if player_in_range and can_interact:
interact()
func interact() -> void:
# 子类重写此方法实现具体交互逻辑
print("", name, " 交互")
EventSystem.emit_event(EventNames.OBJECT_INTERACTED, {
"object": self,
"interaction_type": "default"
})
```
## 🎨 资源过滤设置
### 纹理过滤规范
所有像素艺术资源必须使用最近邻过滤:
```gdscript
# 在导入设置中或代码中设置
func _setup_pixel_perfect_texture(texture: Texture2D) -> void:
if texture is ImageTexture:
var image = texture.get_image()
image.generate_mipmaps(false)
# 在导入设置中设置Filter为Off
```
### 导入设置模板
对于所有精灵资源,在导入设置中:
- **Filter**: Off (关闭)
- **Mipmaps**: Off (关闭)
- **Fix Alpha Border**: On (开启)
## 🔧 性能优化要求
### 节点缓存
```gdscript
# ✅ 正确:使用@onready缓存节点引用
@onready var sprite: Sprite2D = $Sprite2D
@onready var collision: CollisionShape2D = $CollisionShape2D
func _process(delta: float) -> void:
sprite.modulate.a = 0.5 # 使用缓存的引用
# ❌ 错误在_process中重复获取节点
func _process(delta: float) -> void:
$Sprite2D.modulate.a = 0.5 # 每帧都要查找节点
```
### 事件频率控制
```gdscript
# 控制事件发送频率
var last_event_time: float = 0.0
const EVENT_INTERVAL: float = 0.1 # 100ms间隔
func _process(delta: float) -> void:
var current_time = Time.get_time_dict_from_system()
if current_time - last_event_time >= EVENT_INTERVAL:
EventSystem.emit_event(EventNames.POSITION_UPDATE, {
"position": global_position
})
last_event_time = current_time
```
---
**记住:遵循这些实现细节规范可以确保游戏对象的一致性和性能!**

View File

@@ -0,0 +1,312 @@
# API接口测试指南
**更新日期**: 2025-12-25
**适用版本**: API v1.1.1
---
## 🎯 测试概述
本指南提供了完整的API接口测试方案包括Godot内置测试和独立的Python测试脚本确保在不同环境下都能有效验证API功能。
---
## 📋 测试工具对比
| 测试工具 | 适用场景 | 优势 | 使用难度 |
|----------|----------|------|----------|
| **Python快速测试** | 日常检查 | 快速、简单 | ⭐ |
| **Python完整测试** | 全面验证 | 覆盖全面、详细 | ⭐⭐ |
| **Godot内置测试** | 引擎环境 | 真实环境、UI测试 | ⭐⭐⭐ |
| **简单连接测试** | 基础检查 | 最小依赖 | ⭐ |
---
## 🚀 快速开始
### 1. Python测试推荐
#### 安装依赖
```bash
cd tests/api
pip install -r requirements.txt
```
#### 运行快速测试
```bash
# Windows
run_tests.bat
# Linux/Mac
./run_tests.sh
# 或直接运行
python quick_test.py
```
### 2. Godot测试
#### 运行API测试脚本
```gdscript
# 在Godot中运行
var api_test = preload("res://scripts/network/ApiTestScript.gd").new()
add_child(api_test)
```
#### 运行UI测试
```bash
# 打开Godot项目
# 运行 tests/auth/auth_ui_test.tscn 场景
```
---
## 📊 测试类型详解
### 1. 快速测试 (`quick_test.py`)
**用途**: 日常开发中的快速验证
**时间**: 约30秒
**覆盖**: 基础API端点
```bash
python tests/api/quick_test.py
```
**测试内容**:
- ✅ 服务器状态检查
- ✅ 邮箱验证码发送
- ✅ 用户登录/注册
- ✅ 基础错误处理
### 2. 完整测试 (`api_client_test.py`)
**用途**: 发布前的全面验证
**时间**: 约2-3分钟
**覆盖**: 所有业务流程
```bash
python tests/api/api_client_test.py
```
**测试内容**:
- 🔄 完整的用户注册流程
- 🔄 邮箱验证流程
- 🔄 登录流程(密码+验证码)
- 🔄 密码重置流程
- 🔄 错误场景测试
- 🔄 频率限制测试
### 3. Godot内置测试
**用途**: 引擎环境下的真实测试
**时间**: 根据测试场景而定
**覆盖**: UI交互和网络请求
#### API测试脚本
```gdscript
# 文件: scripts/network/ApiTestScript.gd
# 功能: 验证NetworkManager和ResponseHandler
```
#### UI测试场景
```gdscript
# 文件: tests/auth/auth_ui_test.tscn
# 功能: 测试认证界面的各种响应情况
```
---
## 🔧 测试配置
### API服务器配置
```python
# 默认配置
API_BASE_URL = "https://whaletownend.xinghangee.icu"
# 本地开发配置
API_BASE_URL = "http://localhost:3000"
```
### 测试数据配置
```python
# 测试用户信息
TEST_EMAIL = "test@example.com"
TEST_USERNAME = "testuser"
TEST_PASSWORD = "password123"
```
### 超时配置
```python
DEFAULT_TIMEOUT = 30 # 秒
```
---
## 📈 测试结果解读
### 成功标志
-**测试通过** - 功能正常
- 🧪 **测试模式** - 开发环境,验证码在响应中返回
- 🔑 **获取验证码** - 成功获取到测试验证码
### 警告标志
- ⚠️ **资源冲突** - 409状态码用户名/邮箱已存在
-**频率限制** - 429状态码请求过于频繁
### 错误标志
-**测试失败** - 功能异常,需要检查
- 🔌 **连接失败** - 网络问题或服务器不可用
- 📊 **状态码异常** - HTTP状态码不符合预期
### 示例输出解读
```
🧪 测试: 发送邮箱验证码
📡 POST https://whaletownend.xinghangee.icu/auth/send-email-verification
📦 数据: {"email": "test@example.com"}
📊 状态码: 206
🧪 测试模式响应
🔑 验证码: 123456
✅ 测试通过
```
**解读**:
- 请求成功发送到正确的端点
- 返回206状态码表示测试模式
- 成功获取验证码123456
- 整体测试通过
---
## 🐛 故障排除
### 常见问题及解决方案
#### 1. 连接失败
**症状**: `❌ 连接失败``网络连接异常`
**解决方案**:
```bash
# 检查网络连接
ping whaletownend.xinghangee.icu
# 检查服务器状态
curl https://whaletownend.xinghangee.icu
# 检查防火墙设置
```
#### 2. 频率限制
**症状**: `⏰ 请求过于频繁``429状态码`
**解决方案**:
- 等待冷却时间通常1分钟
- 使用不同的测试邮箱
- 检查API频率限制配置
#### 3. 验证码错误
**症状**: `验证码错误或已过期`
**解决方案**:
- 确保使用最新获取的验证码
- 检查验证码是否在5分钟有效期内
- 在测试模式下使用响应中返回的验证码
#### 4. 参数验证失败
**症状**: `400状态码``参数验证失败`
**解决方案**:
- 检查请求参数格式
- 确认必填字段都已提供
- 验证邮箱、用户名格式是否正确
#### 5. Python依赖问题
**症状**: `ModuleNotFoundError: No module named 'requests'`
**解决方案**:
```bash
# 安装依赖
pip install requests
# 或使用requirements.txt
pip install -r tests/api/requirements.txt
# 检查Python版本
python --version
```
---
## 📝 测试最佳实践
### 1. 测试前准备
- 确认API服务器正常运行
- 检查网络连接稳定
- 准备测试数据(邮箱、用户名等)
### 2. 测试执行
- 按照从简单到复杂的顺序执行测试
- 记录测试结果和异常情况
- 对失败的测试进行重试验证
### 3. 测试后分析
- 分析测试结果,识别问题模式
- 更新测试用例覆盖新发现的场景
- 文档化测试发现的问题和解决方案
### 4. 持续集成
- 将测试脚本集成到CI/CD流程
- 设置自动化测试触发条件
- 建立测试结果通知机制
---
## 🔄 测试流程建议
### 开发阶段
1. **快速测试** - 每次代码修改后运行
2. **功能测试** - 新功能开发完成后运行
3. **回归测试** - 修复bug后运行
### 测试阶段
1. **完整测试** - 每日构建后运行
2. **压力测试** - 定期运行频率限制测试
3. **兼容性测试** - 不同环境下运行测试
### 发布阶段
1. **预发布测试** - 生产环境部署前运行
2. **冒烟测试** - 生产环境部署后运行
3. **监控测试** - 生产环境持续监控
---
## 📚 相关文档
- [API文档](api-documentation.md) - 完整的API接口说明
- [API更新日志](api_update_log.md) - 最新的API变更记录
- [项目结构说明](project_structure.md) - 项目整体架构
- [网络管理器设置](network_manager_setup.md) - Godot网络配置
---
## 🤝 贡献指南
### 添加新测试
1. 在对应的测试文件中添加新的测试方法
2. 遵循现有的测试模式和命名规范
3. 添加适当的错误处理和结果验证
4. 更新相关文档
### 报告问题
1. 提供详细的错误信息和复现步骤
2. 包含测试环境信息Python版本、操作系统等
3. 附上相关的日志和截图
### 改进建议
1. 提出测试覆盖的改进建议
2. 优化测试执行效率的方案
3. 增强测试结果可读性的想法
---
**测试愉快!🎉**

View File

@@ -0,0 +1,362 @@
# NetworkManager 设置指南
## 概述
NetworkManager 是一个统一的网络请求管理器提供了简洁的API接口和统一的错误处理机制。配合 ResponseHandler可以大大简化网络请求的处理逻辑。
## 🚀 快速设置
### 1. 设置AutoLoad
在Godot编辑器中
1. 打开 `Project``Project Settings`
2. 切换到 `AutoLoad` 标签
3. 添加新的AutoLoad
- **Path**: `res://core/managers/NetworkManager.gd`
- **Name**: `NetworkManager`
- **Singleton**: ✅ 勾选
### 2. 项目设置文件配置
`project.godot` 文件中会自动添加:
```ini
[autoload]
NetworkManager="*res://core/managers/NetworkManager.gd"
```
### 3. 验证设置
在任何脚本中可以直接使用:
```gdscript
func _ready():
# 直接访问全局单例
var request_id = NetworkManager.login("username", "password", callback)
print("请求ID: ", request_id)
```
## 📚 使用方法
### 基本用法
```gdscript
# 1. 简单的GET请求
var request_id = NetworkManager.get_app_status(func(success, data, error_info):
if success:
print("应用状态: ", data)
else:
print("获取状态失败: ", error_info)
)
# 2. 用户登录
NetworkManager.login("username", "password", func(success, data, error_info):
if success:
print("登录成功: ", data.data.user.username)
else:
print("登录失败: ", error_info.message)
)
# 3. 发送验证码
NetworkManager.send_email_verification("test@example.com", func(success, data, error_info):
if success:
print("验证码已发送")
else:
print("发送失败: ", error_info.message)
)
```
### 配合ResponseHandler使用
```gdscript
# 在回调函数中使用ResponseHandler处理响应
func _on_login_response(success: bool, data: Dictionary, error_info: Dictionary):
# 使用ResponseHandler统一处理
var result = ResponseHandler.handle_login_response(success, data, error_info)
# 显示Toast消息
show_toast(result.message, result.success)
# 执行自定义动作
if result.custom_action.is_valid():
result.custom_action.call()
# 处理成功情况
if result.success:
# 登录成功的处理逻辑
login_success.emit(username)
```
### 全局事件监听
```gdscript
func _ready():
# 监听全局网络事件
NetworkManager.request_completed.connect(_on_global_request_completed)
NetworkManager.request_failed.connect(_on_global_request_failed)
func _on_global_request_completed(request_id: String, success: bool, data: Dictionary):
print("全局请求完成: ", request_id)
# 可以在这里隐藏全局加载指示器
func _on_global_request_failed(request_id: String, error_type: String, message: String):
print("全局请求失败: ", request_id, " - ", message)
# 可以在这里显示全局错误提示
```
## 🔧 高级功能
### 请求管理
```gdscript
# 取消特定请求
var request_id = NetworkManager.login("user", "pass", callback)
NetworkManager.cancel_request(request_id)
# 取消所有请求
NetworkManager.cancel_all_requests()
# 检查请求状态
if NetworkManager.is_request_active(request_id):
print("请求仍在进行中")
# 获取活动请求数量
print("当前活动请求: ", NetworkManager.get_active_request_count())
```
### 自定义请求
```gdscript
# 发送自定义POST请求
var custom_data = {
"custom_field": "custom_value"
}
var request_id = NetworkManager.post_request("/custom/endpoint", custom_data, func(success, data, error_info):
print("自定义请求完成")
)
# 发送自定义GET请求
NetworkManager.get_request("/custom/data", func(success, data, error_info):
print("获取自定义数据")
)
```
## 📋 API接口列表
### 认证相关
| 方法 | 参数 | 说明 |
|------|------|------|
| `login(identifier, password, callback)` | 用户标识符、密码、回调函数 | 用户登录 |
| `verification_code_login(identifier, code, callback)` | 用户标识符、验证码、回调函数 | 验证码登录 |
| `send_login_verification_code(identifier, callback)` | 用户标识符、回调函数 | 发送登录验证码 |
| `register(username, password, nickname, email, code, callback)` | 注册信息、回调函数 | 用户注册 |
| `send_email_verification(email, callback)` | 邮箱、回调函数 | 发送邮箱验证码 |
| `verify_email(email, code, callback)` | 邮箱、验证码、回调函数 | 验证邮箱 |
### 通用请求
| 方法 | 参数 | 说明 |
|------|------|------|
| `get_request(endpoint, callback, timeout)` | 端点、回调函数、超时时间 | GET请求 |
| `post_request(endpoint, data, callback, timeout)` | 端点、数据、回调函数、超时时间 | POST请求 |
| `put_request(endpoint, data, callback, timeout)` | 端点、数据、回调函数、超时时间 | PUT请求 |
| `delete_request(endpoint, callback, timeout)` | 端点、回调函数、超时时间 | DELETE请求 |
### 请求管理
| 方法 | 参数 | 说明 |
|------|------|------|
| `cancel_request(request_id)` | 请求ID | 取消特定请求 |
| `cancel_all_requests()` | 无 | 取消所有请求 |
| `is_request_active(request_id)` | 请求ID | 检查请求是否活动 |
| `get_active_request_count()` | 无 | 获取活动请求数量 |
| `get_request_info(request_id)` | 请求ID | 获取请求详细信息 |
## 🎯 ResponseHandler 使用
### 支持的响应类型
| 方法 | 说明 |
|------|------|
| `handle_login_response()` | 处理登录响应 |
| `handle_verification_code_login_response()` | 处理验证码登录响应 |
| `handle_send_verification_code_response()` | 处理发送验证码响应 |
| `handle_send_login_code_response()` | 处理发送登录验证码响应 |
| `handle_register_response()` | 处理注册响应 |
| `handle_verify_email_response()` | 处理邮箱验证响应 |
| `handle_network_test_response()` | 处理网络测试响应 |
| `handle_response(operation_type, ...)` | 通用响应处理 |
### ResponseResult 结构
```gdscript
class ResponseResult:
var success: bool # 是否成功
var message: String # 显示消息
var toast_type: String # Toast类型 ("success" 或 "error")
var data: Dictionary # 响应数据
var should_show_toast: bool # 是否显示Toast
var custom_action: Callable # 自定义动作
```
## 🔄 迁移指南
### 从旧版AuthScene迁移
#### 旧代码:
```gdscript
func send_login_request(username: String, password: String):
var url = API_BASE_URL + "/auth/login"
var headers = ["Content-Type: application/json"]
var body = JSON.stringify({
"username": username,
"password": password
})
current_request_type = "login"
var error = http_request.request(url, headers, HTTPClient.METHOD_POST, body)
if error != OK:
show_toast('网络请求失败', false)
restore_button(login_btn, "密码登录")
current_request_type = ""
```
#### 新代码:
```gdscript
func send_login_request(username: String, password: String):
NetworkManager.login(username, password, _on_login_response)
func _on_login_response(success: bool, data: Dictionary, error_info: Dictionary):
var result = ResponseHandler.handle_login_response(success, data, error_info)
show_toast(result.message, result.success)
if result.success:
login_success.emit(username)
```
### 迁移步骤
1. **设置AutoLoad**按照上述步骤设置NetworkManager为AutoLoad
2. **替换请求方法**将直接的HTTP请求替换为NetworkManager调用
3. **统一响应处理**使用ResponseHandler处理所有响应
4. **移除重复代码**:删除重复的错误处理和请求构建代码
5. **测试功能**:确保所有功能正常工作
## 🧪 测试
### 单元测试示例
```gdscript
extends GutTest
func test_network_manager_login():
var network_manager = NetworkManager.new()
var callback_called = false
var callback_success = false
var callback = func(success, data, error_info):
callback_called = true
callback_success = success
var request_id = network_manager.login("testuser", "password", callback)
assert_ne(request_id, "", "应该返回有效的请求ID")
# 等待请求完成
await get_tree().create_timer(2.0).timeout
assert_true(callback_called, "回调函数应该被调用")
```
### 集成测试
```gdscript
func test_complete_login_flow():
# 1. 发送登录验证码
var code_sent = false
NetworkManager.send_login_verification_code("test@example.com", func(success, data, error_info):
code_sent = success
)
await get_tree().create_timer(1.0).timeout
assert_true(code_sent, "验证码应该发送成功")
# 2. 使用验证码登录
var login_success = false
NetworkManager.verification_code_login("test@example.com", "123456", func(success, data, error_info):
login_success = success
)
await get_tree().create_timer(1.0).timeout
assert_true(login_success, "验证码登录应该成功")
```
## 🔍 调试
### 启用详细日志
在NetworkManager中所有请求都会输出详细的调试信息
```
=== 发送网络请求 ===
请求ID: req_1
URL: https://whaletownend.xinghangee.icu/auth/login
方法: POST
Headers: ["Content-Type: application/json"]
Body: {"username":"testuser","password":"password123"}
发送结果: 0
=== 网络请求完成 ===
请求ID: req_1
结果: 0
状态码: 200
响应头: ["content-type: application/json"]
响应体长度: 156 字节
响应内容: {"success":true,"data":{"user":{"username":"testuser"}}}
```
### 常见问题
1. **请求ID为空**检查NetworkManager是否正确设置为AutoLoad
2. **回调未调用**检查网络连接和API地址是否正确
3. **解析错误**检查服务器返回的JSON格式是否正确
## 📈 性能优化
### 请求池管理
NetworkManager自动管理请求资源
- 自动清理完成的请求
- 防止内存泄漏
- 支持请求取消
### 最佳实践
1. **及时取消不需要的请求**
2. **使用合适的超时时间**
3. **避免同时发送大量请求**
4. **在场景切换时取消活动请求**
```gdscript
func _exit_tree():
# 场景退出时取消所有请求
NetworkManager.cancel_all_requests()
```
## 🎉 总结
使用NetworkManager和ResponseHandler的优势
-**代码简洁**:一行代码发送请求
-**统一处理**:所有错误情况统一处理
-**易于维护**网络逻辑与UI逻辑分离
-**功能强大**:支持请求管理、超时、取消等
-**调试友好**:详细的日志和错误信息
-**类型安全**:明确的回调参数类型
-**可扩展**易于添加新的API接口
通过这套统一的网络管理系统,你的项目将拥有更好的代码结构和更强的可维护性!