Files
whale-town/.kiro/specs/godot-ai-town-game/design.md
2025-12-05 19:00:14 +08:00

712 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 设计文档
## 概述
本项目是一款基于 Godot 4.x 引擎开发的 2D 多人在线 AI 小镇游戏,采用客户端-服务器架构。游戏的核心特性是持久化的多人世界,玩家创建的角色在玩家离线时会作为 NPC 继续存在于游戏世界中。游戏优先支持网页端HTML5 导出),并预留移动端适配接口。
### 技术栈
- **游戏引擎**: Godot 4.x
- **编程语言**: GDScript
- **网络协议**: WebSocket (用于实时通信)
- **数据格式**: JSON (用于数据序列化)
- **导出平台**: HTML5 (Web), 预留 Android/iOS 支持
- **后端服务**: 简单的 WebSocket 服务器 (可使用 Node.js + ws 或 Python + websockets)
## 架构
### 整体架构
游戏采用客户端-服务器架构,分为以下主要层次:
```
┌─────────────────────────────────────────┐
│ 客户端 (Godot HTML5) │
├─────────────────────────────────────────┤
│ 表现层 (UI/Rendering) │
│ ├─ 场景渲染 │
│ ├─ UI 界面 │
│ └─ 动画系统 │
├─────────────────────────────────────────┤
│ 游戏逻辑层 │
│ ├─ 角色控制器 │
│ ├─ 对话系统 │
│ ├─ 输入处理 │
│ └─ 状态管理 │
├─────────────────────────────────────────┤
│ 网络层 │
│ ├─ WebSocket 客户端 │
│ ├─ 消息序列化/反序列化 │
│ └─ 状态同步 │
└─────────────────────────────────────────┘
↕ WebSocket
┌─────────────────────────────────────────┐
│ 服务器 (WebSocket Server) │
├─────────────────────────────────────────┤
│ 连接管理 │
│ ├─ 客户端连接池 │
│ ├─ 身份验证 │
│ └─ 心跳检测 │
├─────────────────────────────────────────┤
│ 游戏状态管理 │
│ ├─ 世界状态 │
│ ├─ 角色状态 │
│ └─ 消息广播 │
├─────────────────────────────────────────┤
│ 数据持久化 │
│ ├─ 角色数据存储 │
│ ├─ 世界状态存储 │
│ └─ JSON 文件系统 │
└─────────────────────────────────────────┘
```
### 客户端架构
客户端采用 Godot 的场景树结构,主要节点组织如下:
```
Main (Node)
├─ NetworkManager (Node) - 网络连接管理
├─ GameStateManager (Node) - 游戏状态管理
├─ UILayer (CanvasLayer) - UI 层
│ ├─ LoginScreen (Control) - 登录界面
│ ├─ CharacterCreation (Control) - 角色创建界面
│ ├─ HUD (Control) - 游戏内 UI
│ └─ DialogueBox (Control) - 对话框
└─ GameWorld (Node2D) - 游戏世界
├─ TileMap (TileMap) - 场景地图
├─ Characters (Node2D) - 角色容器
│ ├─ PlayerCharacter (CharacterBody2D) - 本地玩家
│ └─ RemoteCharacter (CharacterBody2D) - 其他角色
└─ Camera (Camera2D) - 摄像机
```
### 服务器架构
服务器采用事件驱动架构,主要模块包括:
- **ConnectionManager**: 管理 WebSocket 连接
- **AuthenticationService**: 处理玩家身份验证
- **WorldState**: 维护游戏世界状态
- **CharacterManager**: 管理所有角色(在线/离线)
- **MessageRouter**: 路由和广播消息
- **PersistenceService**: 数据持久化服务
## 组件和接口
### 1. 网络管理器 (NetworkManager)
**职责**: 管理客户端与服务器的 WebSocket 连接
**接口**:
```gdscript
class_name NetworkManager extends Node
signal connected_to_server()
signal disconnected_from_server()
signal connection_error(error: String)
signal message_received(message: Dictionary)
func connect_to_server(url: String) -> void
func disconnect_from_server() -> void
func send_message(message: Dictionary) -> void
func is_connected() -> bool
```
**消息协议**:
所有消息使用 JSON 格式,包含以下字段:
```json
{
"type": "message_type",
"data": {},
"timestamp": 1234567890
}
```
消息类型包括:
- `auth_request`: 身份验证请求
- `auth_response`: 身份验证响应
- `character_create`: 创建角色
- `character_move`: 角色移动
- `character_state`: 角色状态更新
- `dialogue_send`: 发送对话
- `world_state`: 世界状态同步
### 2. 角色控制器 (CharacterController)
**职责**: 处理角色的移动、动画和状态
**接口**:
```gdscript
class_name CharacterController extends CharacterBody2D
var character_id: String
var character_name: String
var is_online: bool
var move_speed: float = 200.0
func move_to(direction: Vector2) -> void
func set_position_smooth(target_pos: Vector2) -> void
func play_animation(anim_name: String) -> void
func set_online_status(online: bool) -> void
```
**状态**:
- `idle`: 静止状态
- `walking`: 行走状态
- `talking`: 对话状态
### 3. 对话系统 (DialogueSystem)
**职责**: 管理角色之间的对话交互
**接口**:
```gdscript
class_name DialogueSystem extends Node
signal dialogue_started(character_id: String)
signal dialogue_ended()
signal message_received(sender: String, message: String)
func start_dialogue(target_character_id: String) -> void
func send_message(message: String) -> void
func end_dialogue() -> void
func show_bubble(character_id: String, message: String, duration: float) -> void
```
**对话模式**:
- **直接对话**: 玩家与另一个角色一对一对话
- **气泡对话**: 附近角色的对话以气泡形式显示
### 4. 输入处理器 (InputHandler)
**职责**: 处理多平台输入(键盘、触摸、虚拟摇杆)
**接口**:
```gdscript
class_name InputHandler extends Node
signal move_input(direction: Vector2)
signal interact_input()
signal ui_input(action: String)
func get_move_direction() -> Vector2
func is_interact_pressed() -> bool
func setup_virtual_controls() -> void
```
**输入映射**:
- **桌面端**: WASD/方向键移动E 键交互
- **移动端**: 虚拟摇杆移动,交互按钮
### 5. 游戏状态管理器 (GameStateManager)
**职责**: 管理游戏的全局状态和场景切换
**接口**:
```gdscript
class_name GameStateManager extends Node
enum GameState {
LOGIN,
CHARACTER_CREATION,
IN_GAME,
DISCONNECTED
}
var current_state: GameState
var player_data: Dictionary
func change_state(new_state: GameState) -> void
func save_player_data() -> void
func load_player_data() -> Dictionary
```
### 6. 世界管理器 (WorldManager)
**职责**: 管理游戏世界中的所有角色和对象
**接口**:
```gdscript
class_name WorldManager extends Node
var characters: Dictionary = {} # character_id -> CharacterController
func spawn_character(character_data: Dictionary) -> void
func remove_character(character_id: String) -> void
func update_character_state(character_id: String, state: Dictionary) -> void
func get_nearby_characters(position: Vector2, radius: float) -> Array
```
## 数据模型
### 角色数据 (Character Data)
```gdscript
{
"id": "unique_character_id",
"name": "角色名称",
"owner_id": "player_account_id",
"position": {
"x": 100.0,
"y": 200.0
},
"is_online": true,
"appearance": {
"sprite": "character_01",
"color": "#FFFFFF"
},
"created_at": 1234567890,
"last_seen": 1234567890
}
```
### 世界状态 (World State)
```gdscript
{
"scene_id": "datawhale_office",
"characters": [
//
],
"timestamp": 1234567890
}
```
### 对话消息 (Dialogue Message)
```gdscript
{
"sender_id": "character_id",
"receiver_id": "character_id", // 广
"message": "对话内容",
"timestamp": 1234567890
}
```
## 正确性属性
*属性是一个特征或行为,应该在系统的所有有效执行中保持为真——本质上是关于系统应该做什么的正式陈述。属性作为人类可读规范和机器可验证正确性保证之间的桥梁。*
### 属性 1: 角色创建唯一性
*对于任意*两个成功创建的角色,它们的角色 ID 应该是唯一的,不会发生冲突
**验证需求: 1.5**
### 属性 2: 角色移动能力
*对于任意*创建或加载到场景的角色,该角色应该具有基础移动能力(可以响应移动指令)
**验证需求: 2.1**
### 属性 3: 位置更新同步
*对于任意*角色的移动操作,执行移动后角色的位置坐标应该被更新,并且该更新应该同步到所有连接的客户端
**验证需求: 2.2**
### 属性 4: 碰撞检测
*对于任意*角色和障碍物,当角色尝试移动到障碍物位置时,系统应该阻止该移动,角色位置保持不变
**验证需求: 2.4**
### 属性 5: 并发移动独立性
*对于任意*多个同时移动的角色,每个角色的移动应该独立处理,一个角色的移动不应影响其他角色的移动逻辑
**验证需求: 2.5**
### 属性 6: 对话触发
*对于任意*两个角色,当一个角色接近另一个角色并触发交互时,系统应该显示对话界面
**验证需求: 3.1**
### 属性 7: 消息传递完整性
*对于任意*对话消息,当玩家发送消息时,该消息应该被传递给接收方,并在发送方和接收方的界面上都正确显示
**验证需求: 3.3**
### 属性 8: 对话状态恢复
*对于任意*进行中的对话,当对话结束时,系统应该关闭对话界面并将游戏状态恢复到对话前的正常状态
**验证需求: 3.4**
### 属性 9: 对话可见性
*对于任意*两个角色之间的对话,附近的其他角色应该能够看到对话气泡显示在对话角色上方
**验证需求: 3.5**
### 属性 10: 场景碰撞检测
*对于任意*玩家角色和场景元素(如桌椅、墙壁),当玩家尝试移动到场景元素位置时,系统应该正确处理碰撞并阻止穿透
**验证需求: 4.5**
### 属性 11: 键盘输入响应
*对于任意*有效的键盘移动输入(方向键或 WASD系统应该将玩家角色移动到相应方向并将移动数据同步到服务器
**验证需求: 5.1**
### 属性 12: 触摸输入响应
*对于任意*有效的触摸移动输入(虚拟摇杆),系统应该将玩家角色移动到指定方向,并将移动数据同步到服务器
**验证需求: 5.2**
### 属性 13: 移动动画同步
*对于任意*角色的移动操作,系统应该播放相应的移动动画,并在所有客户端同步显示该动画
**验证需求: 5.5**
### 属性 14: 响应式布局适配
*对于任意*不同分辨率的浏览器窗口,游戏画面应该自动调整尺寸以适应窗口大小,保持可玩性
**验证需求: 6.3, 7.2**
### 属性 15: 窗口动态调整
*对于任意*浏览器窗口大小的改变,游戏系统应该动态调整游戏画面比例,保持界面元素的可访问性
**验证需求: 6.4**
### 属性 16: 数据序列化往返
*对于任意*游戏数据对象,序列化为 JSON 后再反序列化应该得到等价的对象(往返一致性)
**验证需求: 7.3, 9.5**
### 属性 17: 设备类型检测
*对于任意*设备类型(桌面或移动),系统应该正确检测设备类型并应用相应的控制方案(键盘或触摸)
**验证需求: 7.5**
### 属性 18: 角色数据持久化
*对于任意*创建的角色,角色数据应该被保存到服务器,后续登录时应该能够恢复相同的角色数据
**验证需求: 9.1, 9.2**
### 属性 19: 状态同步
*对于任意*角色位置或状态的改变,系统应该将更新同步到服务器,确保数据一致性
**验证需求: 9.4**
### 属性 20: 移动设备 UI 适配
*对于任意*在移动设备上运行的游戏UI 元素大小应该调整以适应触摸操作(按钮足够大,间距合理)
**验证需求: 10.4**
### 属性 21: 错误提示显示
*对于任意*操作失败的情况,系统应该显示明确的错误提示信息,告知用户失败原因
**验证需求: 10.5**
### 属性 22: 在线角色显示
*对于任意*玩家进入游戏场景时,系统应该显示所有当前在线玩家的角色
**验证需求: 11.1**
### 属性 23: 离线角色显示
*对于任意*玩家进入游戏场景时,系统应该显示所有离线玩家的角色作为 NPC
**验证需求: 11.2**
### 属性 24: 上线状态切换
*对于任意*玩家上线事件,系统应该在场景中显示该玩家的角色,并将其标记为在线状态
**验证需求: 11.3**
### 属性 25: 下线状态切换
*对于任意*玩家下线事件,系统应该将该玩家的角色转换为离线 NPC 状态,但角色继续存在于场景中
**验证需求: 11.4**
### 属性 26: 角色状态视觉区分
*对于任意*显示的角色,系统应该通过视觉标识(如颜色、图标)区分在线玩家和离线角色
**验证需求: 11.5**
### 属性 27: 网络连接建立
*对于任意*玩家登录操作,系统应该尝试建立与服务器的网络连接
**验证需求: 12.1**
### 属性 28: 断线重连
*对于任意*网络连接中断事件,系统应该显示断线提示并自动尝试重新连接到服务器
**验证需求: 12.3**
### 属性 29: 操作确认
*对于任意*玩家执行的操作,系统应该将操作数据发送到服务器并等待接收确认响应
**验证需求: 12.4**
### 属性 30: 服务器更新同步
*对于任意*服务器推送的更新消息,客户端应该实时更新本地游戏状态以反映服务器的变化
**验证需求: 12.5**
## 错误处理
### 网络错误处理
**连接失败**:
- 显示友好的错误提示
- 提供重试按钮
- 记录错误日志用于调试
**连接中断**:
- 自动尝试重连(最多 3 次)
- 显示断线状态指示器
- 缓存未发送的操作,重连后重新发送
**消息发送失败**:
- 重试机制(指数退避)
- 超时后通知用户
- 保持本地状态一致性
### 数据验证错误
**角色创建验证**:
- 名称长度限制2-20 字符)
- 禁止特殊字符和空白字符
- 检查名称唯一性
**输入验证**:
- 对话消息长度限制1-500 字符)
- 过滤恶意输入
- 防止注入攻击
### 状态不一致处理
**客户端-服务器状态不一致**:
- 定期同步状态(每 5 秒)
- 服务器状态为权威状态
- 客户端预测 + 服务器校正
**角色位置冲突**:
- 服务器检测位置冲突
- 强制回退到有效位置
- 通知客户端更新
## 测试策略
### 单元测试
使用 Godot 的 GUT (Godot Unit Test) 框架进行单元测试。
**测试覆盖范围**:
- 数据模型的序列化/反序列化
- 输入处理逻辑
- 状态管理器的状态转换
- 消息协议的编码/解码
**示例测试**:
```gdscript
# test_character_data.gd
extends GutTest
func test_character_serialization():
var character = {
"id": "test_123",
"name": "测试角色",
"position": {"x": 100.0, "y": 200.0}
}
var json_str = JSON.stringify(character)
var parsed = JSON.parse_string(json_str)
assert_eq(parsed["id"], character["id"])
assert_eq(parsed["name"], character["name"])
```
### 属性基础测试
使用 GDScript 实现简单的属性测试框架,或使用社区提供的属性测试库。
**测试库**: 自定义实现或使用 Godot 社区的属性测试工具
**测试配置**: 每个属性测试至少运行 100 次迭代
**测试标注格式**: `# Feature: godot-ai-town-game, Property X: [属性描述]`
**属性测试覆盖**:
1. **属性 1: 角色创建唯一性**
- 生成多个随机角色
- 验证所有角色 ID 唯一
2. **属性 2: 角色移动能力**
- 生成随机角色
- 验证角色可以响应移动指令
3. **属性 3: 位置更新同步**
- 生成随机移动操作
- 验证位置正确更新
4. **属性 4: 碰撞检测**
- 生成随机障碍物和移动路径
- 验证碰撞正确阻止移动
5. **属性 16: 数据序列化往返**
- 生成随机游戏数据对象
- 验证序列化后反序列化得到等价对象
6. **属性 18: 角色数据持久化**
- 生成随机角色数据
- 验证保存后加载得到相同数据
**示例属性测试**:
```gdscript
# test_properties.gd
extends GutTest
# Feature: godot-ai-town-game, Property 16: 数据序列化往返
func test_property_serialization_roundtrip():
for i in range(100):
var random_data = generate_random_character_data()
var serialized = JSON.stringify(random_data)
var deserialized = JSON.parse_string(serialized)
assert_eq_deep(deserialized, random_data,
"序列化往返应该保持数据一致性")
func generate_random_character_data() -> Dictionary:
return {
"id": "char_" + str(randi()),
"name": "角色" + str(randi() % 1000),
"position": {
"x": randf_range(0, 1000),
"y": randf_range(0, 1000)
},
"is_online": randi() % 2 == 0
}
```
### 集成测试
**场景加载测试**:
- 测试 Datawhale 办公室场景正确加载
- 验证所有必需的节点存在
- 检查碰撞层设置正确
**网络集成测试**:
- 启动测试服务器
- 测试客户端连接流程
- 验证消息收发正确
**多客户端测试**:
- 模拟多个客户端连接
- 测试状态同步
- 验证角色互动
### 性能测试
**帧率测试**:
- 测试不同数量角色时的帧率
- 目标: 30+ FPS (10 个角色)
**网络延迟测试**:
- 测试不同网络条件下的响应时间
- 目标: 操作响应 < 200ms
**内存使用测试**:
- 监控长时间运行的内存使用
- 检测内存泄漏
### 跨平台测试
**浏览器兼容性**:
- Chrome (最新版本)
- Firefox (最新版本)
- Safari (最新版本)
- Edge (最新版本)
**设备测试**:
- 桌面 (1920x1080, 1366x768)
- 平板 (iPad, Android 平板)
- 手机 (iOS, Android)
**输入测试**:
- 键盘输入
- 鼠标输入
- 触摸输入
- 虚拟摇杆
## 场景设计
### Datawhale 办公室场景
**场景尺寸**: 2000x1500 像素
**主要区域**:
1. **入口区域**: 门、欢迎标识
2. **工作区**: 办公桌、电脑、椅子
3. **会议区**: 会议桌、白板
4. **休息区**: 沙发、茶水间
5. **展示区**: Datawhale logo、成就墙
**碰撞层设置**:
- Layer 1: 墙壁和固定障碍物
- Layer 2: 家具(可选择性碰撞)
- Layer 3: 角色
- Layer 4: 交互区域
**视觉风格**:
- 2D 俯视角45度等距视角可选
- 简洁的像素艺术或矢量风格
- Datawhale 品牌色: 蓝色系为主
### 资源需求
**图像资源**:
- 角色精灵图4 方向行走动画)
- 场景瓦片集(地板、墙壁、家具)
- UI 元素(按钮、对话框、图标)
- Datawhale logo 和品牌元素
**音频资源** (可选):
- 背景音乐
- 脚步声
- UI 交互音效
- 对话提示音
## 部署和构建
### Web 导出配置
**Godot 导出设置**:
- 目标平台: HTML5
- 导出模板: Godot 4.x Web
- 线程支持: 启用(如果浏览器支持)
- VRAM 压缩: 启用
**Web 服务器要求**:
- 支持 WebSocket
- HTTPS (用于生产环境)
- CORS 配置正确
### 服务器部署
**推荐部署方案**:
- 静态文件: Nginx/Apache 或 CDN
- WebSocket 服务器: Node.js 或 Python
- 数据存储: JSON 文件或轻量级数据库
**环境变量**:
- `SERVER_URL`: WebSocket 服务器地址
- `PORT`: 服务器端口
- `DATA_DIR`: 数据存储目录
### 移动端预留
**响应式设计**:
- 使用 Godot 的 Viewport 缩放
- UI 元素使用相对定位
- 字体大小动态调整
**输入抽象**:
- 统一的输入接口
- 自动检测输入设备
- 虚拟控制器自动显示/隐藏
**跨端数据同步**:
- 统一的数据格式
- 服务器端状态管理
- 客户端无状态设计
## 扩展性考虑
### 未来功能预留
**AI 对话系统**:
- 预留 AI 接口(如 OpenAI API
- 对话历史记录
- 角色个性设置
**更多场景**:
- 场景管理器支持多场景
- 场景切换机制
- 场景间传送
**社交功能**:
- 好友系统
- 私聊功能
- 角色关系网络
### 性能优化预留
**对象池**:
- 角色对象复用
- UI 元素复用
- 减少内存分配
**网络优化**:
- 消息批处理
- 状态差异同步
- 区域兴趣管理AOI
**渲染优化**:
- 视锥剔除
- LOD (细节层次)
- 纹理压缩