# 代码风格指南 ## 概述 本文档定义了 AI Town Game 项目的代码风格和最佳实践。遵循这些规范有助于保持代码的一致性、可读性和可维护性。 ## 命名规范 ### 变量和函数 - 使用 `snake_case` 命名法 - 变量名应该描述性强,避免缩写 - 布尔变量使用 `is_`, `has_`, `can_` 等前缀 ```gdscript # 好的例子 var player_character: CharacterController var is_connected: bool var has_valid_data: bool # 避免的例子 var pc: CharacterController var conn: bool var data: bool ``` ### 类和枚举 - 使用 `PascalCase` 命名法 - 类名应该是名词 - 枚举值使用 `UPPER_CASE` ```gdscript # 类名 class_name NetworkManager class_name CharacterController # 枚举 enum GameState { LOGIN, CHARACTER_CREATION, IN_GAME } ``` ### 常量 - 使用 `UPPER_CASE` 命名法 - 相关常量可以组织在字典中 ```gdscript const MAX_PLAYERS = 50 const DEFAULT_TIMEOUT = 10.0 const COLORS = { "online": Color.GREEN, "offline": Color.GRAY } ``` ### 信号 - 使用 `snake_case` 命名法 - 使用过去时态描述已发生的事件 ```gdscript signal character_spawned(character_id: String) signal connection_established() signal message_received(data: Dictionary) ``` ## 代码组织 ### 文件结构 每个脚本文件应该按以下顺序组织: 1. `extends` 和 `class_name` 声明 2. 类文档注释 3. 信号定义 4. 常量定义 5. 导出变量 6. 公共变量 7. 私有变量 8. 内置函数(`_ready`, `_process` 等) 9. 公共函数 10. 私有函数 ```gdscript extends Node class_name ExampleClass ## 示例类 ## 展示代码组织结构 # 信号 signal data_changed(new_data: Dictionary) # 常量 const MAX_ITEMS = 100 # 导出变量 @export var item_count: int = 0 # 公共变量 var current_state: GameState # 私有变量 var _internal_data: Dictionary = {} func _ready(): """初始化函数""" pass func public_function() -> void: """公共函数""" pass func _private_function() -> void: """私有函数""" pass ``` ### 函数组织 - 相关功能的函数应该放在一起 - 使用注释分隔不同的功能区域 - 私有函数以下划线开头 ```gdscript ## === 网络相关函数 === func connect_to_server() -> void: """连接到服务器""" pass func disconnect_from_server() -> void: """断开服务器连接""" pass func _handle_network_error() -> void: """处理网络错误(私有函数)""" pass ## === UI相关函数 === func show_notification() -> void: """显示通知""" pass ``` ## 注释和文档 ### 类文档 每个类都应该有文档注释,说明其用途和职责: ```gdscript extends Node class_name NetworkManager ## 网络管理器 ## 负责管理客户端与服务器的 WebSocket 连接 ## ## 主要功能: ## - 建立和维护网络连接 ## - 处理消息收发 ## - 管理重连逻辑 ``` ### 函数文档 公共函数应该有详细的文档注释: ```gdscript func spawn_character(character_data: Dictionary, is_player: bool = false) -> CharacterController: """ 在世界中生成角色 @param character_data: 角色数据字典,必须包含 id 和 name 字段 @param is_player: 是否为玩家角色,默认为 false @return: 生成的角色控制器实例,失败时返回 null 示例: var data = {"id": "char_123", "name": "Hero"} var character = spawn_character(data, true) """ pass ``` ### 行内注释 - 解释复杂的逻辑 - 说明为什么这样做,而不是做了什么 - 避免显而易见的注释 ```gdscript # 好的注释 - 解释原因 # 使用指数退避算法避免服务器过载 _reconnect_timer = _reconnect_delay * pow(2, _reconnect_attempts) # 避免的注释 - 重复代码 # 设置重连计时器为延迟时间 _reconnect_timer = _reconnect_delay ``` ## 错误处理 ### 使用统一的错误处理 使用项目的 `ErrorHandler` 类记录错误: ```gdscript # 记录网络错误 ErrorHandler.log_network_error("Connection failed", {"url": server_url}) # 记录游戏逻辑错误 ErrorHandler.log_game_error("Invalid character data", {"character_id": char_id}) ``` ### 防御性编程 - 验证输入参数 - 检查空引用 - 处理边界情况 ```gdscript func update_character_position(character_id: String, position: Vector2) -> void: """更新角色位置""" # 验证输入 if character_id.is_empty(): ErrorHandler.log_game_error("Empty character ID provided") return # 检查角色是否存在 if not characters.has(character_id): ErrorHandler.log_game_error("Character not found", {"id": character_id}) return # 执行更新 var character = characters[character_id] character.set_position_smooth(position) ``` ## 性能最佳实践 ### 避免不必要的计算 ```gdscript # 好的做法 - 缓存计算结果 var distance_squared = position.distance_squared_to(target) if distance_squared < interaction_range_squared: # 执行交互 # 避免的做法 - 重复计算 if position.distance_to(target) < interaction_range: # 执行交互 ``` ### 使用对象池 对于频繁创建和销毁的对象,考虑使用对象池: ```gdscript # 从对象池获取对象而不是创建新对象 var bullet = BulletPool.get_bullet() bullet.initialize(position, direction) ``` ### 合理使用信号 - 避免在每帧都发射信号 - 使用一次性连接(`connect(..., CONNECT_ONE_SHOT)`)当适用时 ## 测试 ### 测试命名 测试函数应该清楚地描述测试内容: ```gdscript func test_character_creation_with_valid_data(): """测试使用有效数据创建角色""" pass func test_network_connection_timeout(): """测试网络连接超时处理""" pass ``` ### 属性测试标注 属性测试必须包含特定的注释格式: ```gdscript ## Feature: godot-ai-town-game, Property 1: 角色创建唯一性 func test_property_character_id_uniqueness(): """ 属性测试:角色创建唯一性 对于任意两个成功创建的角色,它们的角色 ID 应该是唯一的 """ pass ``` ## 配置管理 ### 使用配置类 避免硬编码常量,使用 `GameConfig` 类: ```gdscript # 好的做法 var move_speed = GameConfig.get_character_move_speed() var timeout = GameConfig.NETWORK.connection_timeout # 避免的做法 var move_speed = 200.0 var timeout = 10.0 ``` ## Git 提交规范 ### 提交消息格式 ``` (): [optional body] [optional footer] ``` ### 类型 - `feat`: 新功能 - `fix`: 修复bug - `refactor`: 重构代码 - `docs`: 文档更新 - `test`: 测试相关 - `style`: 代码格式调整 - `perf`: 性能优化 ### 示例 ``` feat(network): add automatic reconnection logic Implement exponential backoff algorithm for reconnection attempts. Maximum 3 attempts with increasing delay between attempts. Closes #123 ``` ## 工具使用 ### 使用工具类 项目提供了多个工具类,应该优先使用: ```gdscript # 使用 Utils 类的工具函数 if Utils.is_string_blank(character_name): return false var unique_id = Utils.generate_unique_id("char_") var label = Utils.create_label_with_shadow("Player Name") # 使用深度比较 if Utils.deep_equals(data1, data2): # 数据相同 ``` ### 性能监控 在关键路径上使用性能监控: ```gdscript # 记录网络延迟 var start_time = Time.get_ticks_msec() # ... 网络操作 ... var latency = Time.get_ticks_msec() - start_time PerformanceMonitor.record_network_latency(latency) ``` ## 总结 遵循这些代码风格指南将有助于: - 提高代码可读性和可维护性 - 减少bug和错误 - 提升团队协作效率 - 保持项目的长期健康发展 所有团队成员都应该熟悉并遵循这些规范。在代码审查时,这些规范也是重要的检查点。