7.7 KiB
7.7 KiB
代码风格指南
概述
本文档定义了 AI Town Game 项目的代码风格和最佳实践。遵循这些规范有助于保持代码的一致性、可读性和可维护性。
命名规范
变量和函数
- 使用
snake_case命名法 - 变量名应该描述性强,避免缩写
- 布尔变量使用
is_,has_,can_等前缀
# 好的例子
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
# 类名
class_name NetworkManager
class_name CharacterController
# 枚举
enum GameState {
LOGIN,
CHARACTER_CREATION,
IN_GAME
}
常量
- 使用
UPPER_CASE命名法 - 相关常量可以组织在字典中
const MAX_PLAYERS = 50
const DEFAULT_TIMEOUT = 10.0
const COLORS = {
"online": Color.GREEN,
"offline": Color.GRAY
}
信号
- 使用
snake_case命名法 - 使用过去时态描述已发生的事件
signal character_spawned(character_id: String)
signal connection_established()
signal message_received(data: Dictionary)
代码组织
文件结构
每个脚本文件应该按以下顺序组织:
extends和class_name声明- 类文档注释
- 信号定义
- 常量定义
- 导出变量
- 公共变量
- 私有变量
- 内置函数(
_ready,_process等) - 公共函数
- 私有函数
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
函数组织
- 相关功能的函数应该放在一起
- 使用注释分隔不同的功能区域
- 私有函数以下划线开头
## === 网络相关函数 ===
func connect_to_server() -> void:
"""连接到服务器"""
pass
func disconnect_from_server() -> void:
"""断开服务器连接"""
pass
func _handle_network_error() -> void:
"""处理网络错误(私有函数)"""
pass
## === UI相关函数 ===
func show_notification() -> void:
"""显示通知"""
pass
注释和文档
类文档
每个类都应该有文档注释,说明其用途和职责:
extends Node
class_name NetworkManager
## 网络管理器
## 负责管理客户端与服务器的 WebSocket 连接
##
## 主要功能:
## - 建立和维护网络连接
## - 处理消息收发
## - 管理重连逻辑
函数文档
公共函数应该有详细的文档注释:
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
行内注释
- 解释复杂的逻辑
- 说明为什么这样做,而不是做了什么
- 避免显而易见的注释
# 好的注释 - 解释原因
# 使用指数退避算法避免服务器过载
_reconnect_timer = _reconnect_delay * pow(2, _reconnect_attempts)
# 避免的注释 - 重复代码
# 设置重连计时器为延迟时间
_reconnect_timer = _reconnect_delay
错误处理
使用统一的错误处理
使用项目的 ErrorHandler 类记录错误:
# 记录网络错误
ErrorHandler.log_network_error("Connection failed", {"url": server_url})
# 记录游戏逻辑错误
ErrorHandler.log_game_error("Invalid character data", {"character_id": char_id})
防御性编程
- 验证输入参数
- 检查空引用
- 处理边界情况
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)
性能最佳实践
避免不必要的计算
# 好的做法 - 缓存计算结果
var distance_squared = position.distance_squared_to(target)
if distance_squared < interaction_range_squared:
# 执行交互
# 避免的做法 - 重复计算
if position.distance_to(target) < interaction_range:
# 执行交互
使用对象池
对于频繁创建和销毁的对象,考虑使用对象池:
# 从对象池获取对象而不是创建新对象
var bullet = BulletPool.get_bullet()
bullet.initialize(position, direction)
合理使用信号
- 避免在每帧都发射信号
- 使用一次性连接(
connect(..., CONNECT_ONE_SHOT))当适用时
测试
测试命名
测试函数应该清楚地描述测试内容:
func test_character_creation_with_valid_data():
"""测试使用有效数据创建角色"""
pass
func test_network_connection_timeout():
"""测试网络连接超时处理"""
pass
属性测试标注
属性测试必须包含特定的注释格式:
## Feature: godot-ai-town-game, Property 1: 角色创建唯一性
func test_property_character_id_uniqueness():
"""
属性测试:角色创建唯一性
对于任意两个成功创建的角色,它们的角色 ID 应该是唯一的
"""
pass
配置管理
使用配置类
避免硬编码常量,使用 GameConfig 类:
# 好的做法
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: 修复bugrefactor: 重构代码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
工具使用
使用工具类
项目提供了多个工具类,应该优先使用:
# 使用 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):
# 数据相同
性能监控
在关键路径上使用性能监控:
# 记录网络延迟
var start_time = Time.get_ticks_msec()
# ... 网络操作 ...
var latency = Time.get_ticks_msec() - start_time
PerformanceMonitor.record_network_latency(latency)
总结
遵循这些代码风格指南将有助于:
- 提高代码可读性和可维护性
- 减少bug和错误
- 提升团队协作效率
- 保持项目的长期健康发展
所有团队成员都应该熟悉并遵循这些规范。在代码审查时,这些规范也是重要的检查点。