Files
whale-town/CODING_STYLE.md
2025-12-05 19:00:14 +08:00

369 lines
7.7 KiB
Markdown

# 代码风格指南
## 概述
本文档定义了 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 提交规范
### 提交消息格式
```
<type>(<scope>): <description>
[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和错误
- 提升团队协作效率
- 保持项目的长期健康发展
所有团队成员都应该熟悉并遵循这些规范。在代码审查时,这些规范也是重要的检查点。