# 开发哲学与最佳实践 本文档阐述了WhaleTown项目的开发哲学和编程最佳实践,旨在指导团队创造高质量、可维护的代码。 ## 🧘 开发哲学 ### 核心理念 - **用户体验至上** - 每个功能都要考虑用户感受 - **代码即文档** - 代码应该自解释,清晰易懂 - **简洁胜于复杂** - 优先选择简单直接的解决方案 - **质量重于速度** - 宁可慢一点,也要做对 ### 设计原则 #### 1. 流畅体验 (Juice or Death) 每个用户交互都必须有视觉反馈和动画效果: ```gdscript # ✅ 正确:为UI交互添加动画 func show_dialog() -> void: dialog.modulate.a = 0.0 dialog.scale = Vector2(0.8, 0.8) dialog.visible = true var tween = create_tween() tween.parallel().tween_property(dialog, "modulate:a", 1.0, 0.3) tween.parallel().tween_property(dialog, "scale", Vector2.ONE, 0.3) tween.set_ease(Tween.EASE_OUT) tween.set_trans(Tween.TRANS_BACK) # ❌ 错误:没有动画的生硬切换 func show_dialog() -> void: dialog.visible = true # 突然出现,体验差 ``` #### 2. 零魔法数字 (Zero Magic Numbers) 所有数值都应该有明确的含义和来源: ```gdscript # ✅ 正确:使用导出变量或配置文件 @export var move_speed: float = 200.0 @export var jump_height: float = 400.0 @export var health_max: int = 100 # 或从配置文件加载 const CONFIG_PATH = "res://data/player_config.json" var config_data: Dictionary func _ready() -> void: config_data = load_config(CONFIG_PATH) move_speed = config_data.get("move_speed", 200.0) # ❌ 错误:硬编码的魔法数字 func _physics_process(delta: float) -> void: velocity.x = input_direction.x * 200 # 200是什么? if position.y > 1000: # 1000代表什么? respawn() ``` #### 3. 函数单一职责 每个函数只做一件事,做好一件事: ```gdscript # ✅ 正确:职责分离 func handle_player_input() -> void: var input_direction = get_input_direction() apply_movement(input_direction) check_interaction_input() func get_input_direction() -> Vector2: return Input.get_vector("move_left", "move_right", "move_up", "move_down") func apply_movement(direction: Vector2) -> void: velocity = direction * move_speed move_and_slide() func check_interaction_input() -> void: if Input.is_action_just_pressed("interact"): try_interact() # ❌ 错误:一个函数做太多事 func handle_everything() -> void: # 处理输入 var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down") # 处理移动 velocity = direction * move_speed move_and_slide() # 处理交互 if Input.is_action_just_pressed("interact"): # 检查交互对象 var interactables = get_nearby_interactables() # 执行交互 for obj in interactables: obj.interact() # 更新UI update_health_bar() # 播放音效 play_footstep_sound() ``` #### 4. 隐藏复杂性 复杂的逻辑应该被封装,对外提供简洁的接口: ```gdscript # ✅ 正确:封装复杂逻辑 class_name NetworkManager func login(username: String, password: String, callback: Callable) -> int: return _make_request("POST", "/auth/login", { "username": username, "password": password }, callback) func _make_request(method: String, endpoint: String, data: Dictionary, callback: Callable) -> int: # 复杂的网络请求逻辑被隐藏 var request = HTTPRequest.new() var request_id = _generate_request_id() # 设置请求头、处理认证、错误重试等复杂逻辑 _setup_request_headers(request) _handle_authentication(request) _setup_retry_logic(request, callback) return request_id # 使用时非常简洁 func _on_login_button_pressed() -> void: NetworkManager.login(username_input.text, password_input.text, _on_login_response) ``` ## 📋 编码最佳实践 ### 1. 类型安全 始终使用严格的类型声明: ```gdscript # ✅ 正确:明确的类型声明 var player_health: int = 100 var move_speed: float = 200.0 var player_name: String = "Player" var inventory_items: Array[Item] = [] var config_data: Dictionary = {} func calculate_damage(base_damage: int, multiplier: float) -> int: return int(base_damage * multiplier) # ❌ 错误:缺少类型信息 var health = 100 # 类型不明确 var speed = 200 # 可能是int也可能是float func calculate_damage(base, mult): # 参数类型不明确 return base * mult # 返回类型不明确 ``` ### 2. 错误处理 主动处理可能的错误情况: ```gdscript # ✅ 正确:完善的错误处理 func load_save_file(file_path: String) -> Dictionary: if not FileAccess.file_exists(file_path): push_warning("存档文件不存在: " + file_path) return {} var file = FileAccess.open(file_path, FileAccess.READ) if file == null: push_error("无法打开存档文件: " + file_path) return {} var json_string = file.get_as_text() file.close() if json_string.is_empty(): push_warning("存档文件为空: " + file_path) return {} var json = JSON.new() var parse_result = json.parse(json_string) if parse_result != OK: push_error("存档文件JSON格式错误: " + file_path) return {} return json.data # ❌ 错误:没有错误处理 func load_save_file(file_path: String) -> Dictionary: var file = FileAccess.open(file_path, FileAccess.READ) var json_string = file.get_as_text() file.close() var json = JSON.new() json.parse(json_string) return json.data # 任何步骤出错都会崩溃 ``` ### 3. 资源管理 及时释放不需要的资源: ```gdscript # ✅ 正确:资源管理 class_name AudioManager var audio_players: Array[AudioStreamPlayer] = [] var max_concurrent_sounds: int = 10 func play_sound(sound: AudioStream, volume: float = 0.0) -> void: # 清理已完成的音频播放器 _cleanup_finished_players() # 限制并发音频数量 if audio_players.size() >= max_concurrent_sounds: _stop_oldest_player() var player = AudioStreamPlayer.new() add_child(player) player.stream = sound player.volume_db = volume player.finished.connect(_on_audio_finished.bind(player)) player.play() audio_players.append(player) func _cleanup_finished_players() -> void: audio_players = audio_players.filter(func(player): return player.playing) func _on_audio_finished(player: AudioStreamPlayer) -> void: audio_players.erase(player) player.queue_free() ``` ### 4. 性能优化 编写高效的代码: ```gdscript # ✅ 正确:性能优化的代码 class_name EnemyManager var enemies: Array[Enemy] = [] var update_timer: float = 0.0 const UPDATE_INTERVAL: float = 0.1 # 每100ms更新一次 func _process(delta: float) -> void: update_timer += delta if update_timer >= UPDATE_INTERVAL: _update_enemies(update_timer) update_timer = 0.0 func _update_enemies(delta_time: float) -> void: # 只更新屏幕附近的敌人 var camera_pos = get_viewport().get_camera_2d().global_position var screen_size = get_viewport().get_visible_rect().size for enemy in enemies: if _is_enemy_near_screen(enemy, camera_pos, screen_size): enemy.update_ai(delta_time) func _is_enemy_near_screen(enemy: Enemy, camera_pos: Vector2, screen_size: Vector2) -> bool: var distance = enemy.global_position.distance_to(camera_pos) var max_distance = screen_size.length() * 0.6 # 屏幕对角线的60% return distance <= max_distance # ❌ 错误:性能问题 func _process(delta: float) -> void: # 每帧更新所有敌人,无论是否可见 for enemy in enemies: enemy.update_ai(delta) # 可能有数百个敌人 # 每帧进行复杂计算 var path = enemy.find_path_to_player() enemy.follow_path(path) ``` ## 🎯 代码审查标准 ### 审查清单 在提交代码前,请检查以下项目: #### 功能性 - [ ] 代码实现了预期功能 - [ ] 处理了边界情况和错误情况 - [ ] 添加了必要的测试用例 #### 可读性 - [ ] 变量和函数名称清晰明确 - [ ] 代码结构逻辑清晰 - [ ] 添加了必要的注释 #### 性能 - [ ] 避免了不必要的计算 - [ ] 正确管理了资源生命周期 - [ ] 使用了合适的数据结构 #### 规范性 - [ ] 遵循了项目命名规范 - [ ] 使用了正确的类型声明 - [ ] 符合架构设计原则 ### 代码示例评分 #### 优秀代码示例 (A级) ```gdscript extends CharacterBody2D class_name Player ## 玩家角色控制器 ## ## 负责处理玩家输入、移动和基础交互 ## 使用事件系统与其他组件通信 @export_group("Movement") @export var move_speed: float = 200.0 @export var acceleration: float = 1000.0 @export var friction: float = 800.0 @export_group("Interaction") @export var interaction_range: float = 50.0 @onready var sprite: Sprite2D = %Sprite2D @onready var animation_player: AnimationPlayer = %AnimationPlayer @onready var interaction_area: Area2D = %InteractionArea var _current_interactable: Interactable = null func _ready() -> void: _setup_interaction_area() _connect_signals() func _physics_process(delta: float) -> void: _handle_movement(delta) func _input(event: InputEvent) -> void: if event.is_action_pressed("interact"): _try_interact() func _handle_movement(delta: float) -> void: var input_direction := _get_movement_input() _apply_movement(input_direction, delta) _update_animation(input_direction) func _get_movement_input() -> Vector2: return Input.get_vector("move_left", "move_right", "move_up", "move_down") func _apply_movement(direction: Vector2, delta: float) -> void: if direction != Vector2.ZERO: velocity = velocity.move_toward(direction * move_speed, acceleration * delta) else: velocity = velocity.move_toward(Vector2.ZERO, friction * delta) move_and_slide() func _update_animation(direction: Vector2) -> void: if direction.length() > 0.1: animation_player.play("walk") sprite.flip_h = direction.x < 0 else: animation_player.play("idle") ``` #### 需要改进的代码 (C级) ```gdscript extends CharacterBody2D var speed = 200 var player var enemies = [] func _ready(): player = self func _process(delta): var dir = Vector2() if Input.is_action_pressed("ui_left"): dir.x -= 1 if Input.is_action_pressed("ui_right"): dir.x += 1 if Input.is_action_pressed("ui_up"): dir.y -= 1 if Input.is_action_pressed("ui_down"): dir.y += 1 velocity = dir * speed move_and_slide() for enemy in enemies: if position.distance_to(enemy.position) < 100: print("near enemy") ``` ## 🚀 持续改进 ### 重构指导原则 1. **小步快跑** - 每次只重构一小部分 2. **测试保护** - 重构前确保有测试覆盖 3. **功能不变** - 重构不改变外部行为 4. **逐步优化** - 持续改进代码质量 ### 技术债务管理 ```gdscript # 使用TODO注释标记技术债务 # TODO: 重构这个函数,职责过多 # FIXME: 这里有性能问题,需要优化 # HACK: 临时解决方案,需要找到更好的方法 # NOTE: 这里的逻辑比较复杂,需要详细注释 ``` --- **记住:优秀的代码不仅能工作,更要易于理解、维护和扩展。追求代码质量是每个开发者的责任!**