# 设计文档 ## 概述 本项目是一款基于 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 (细节层次) - 纹理压缩