创建新工程
This commit is contained in:
369
CODING_STYLE.md
Normal file
369
CODING_STYLE.md
Normal file
@@ -0,0 +1,369 @@
|
||||
# 代码风格指南
|
||||
|
||||
## 概述
|
||||
|
||||
本文档定义了 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和错误
|
||||
- 提升团队协作效率
|
||||
- 保持项目的长期健康发展
|
||||
|
||||
所有团队成员都应该熟悉并遵循这些规范。在代码审查时,这些规范也是重要的检查点。
|
||||
Reference in New Issue
Block a user