Godot 4.x 核心架构原则
为 Godot 4.x 项目设计的核心原则,确保代码的通用性、模块化、可复用性、简洁性。
核心设计原则
1. 通用性优先
- •使用
@export暴露可配置参数,避免硬编码 - •组件应该能在不同场景中复用,不依赖特定父节点
- •通过配置而非代码修改来调整行为
2. 模块化设计
- •单一职责:每个组件只做一件事(Health、Movement、Attack)
- •组件化思维:用小组件组合出复杂行为,避免巨型类
- •信号松耦合:通过信号通信,避免直接调用和硬依赖
3. 可复用性
- •Resource 类:用于存储配置数据(Damage、SkillData)
- •清晰接口:公共方法定义清晰,private方法用
_前缀 - •独立性:组件可以独立测试和使用
4. 简洁实用
- •注重实用性,避免过度设计
- •不为未来需求预先设计
- •代码自解释,复杂逻辑才加注释
5. 继承与钩子方法
- •通用逻辑放基类:所有可复用逻辑在基类实现
- •提供钩子方法:基类提供可重写的钩子方法,让子类定制行为
- •子类最小化重写:子类只重写必要的钩子方法,不复制基类代码
- •信号连接在基类:信号连接只在基类
_ready()中进行,子类不要重复连接 - •避免覆盖 _ready():子类尽量不覆盖
_ready(),如需覆盖必须调用super()
组件模式示例
基础组件模板
gdscript
extends Node
class_name Health
## 可复用的生命值组件
## 通过信号通知状态变化,不依赖特定父节点
signal health_changed(current: float, maximum: float)
signal died()
@export var max_health: float = 100.0
var health: float = max_health:
set(val):
health = clamp(val, 0, max_health)
health_changed.emit(health, max_health)
if health <= 0:
died.emit()
func take_damage(amount: float) -> void:
health -= amount
func heal(amount: float) -> void:
health += amount
Resource 数据类
gdscript
extends Resource
class_name Damage
## 伤害数据配置类
## 可在编辑器中创建 .tres 资源文件
@export var base_damage: float = 10.0
@export var damage_type: String = "physical"
@export_group("Effects")
@export var knockback_force: float = 0.0
@export var stun_duration: float = 0.0
钩子方法模式
gdscript
# 基类 - 提供钩子方法
class_name Hitbox
extends Area2D
## 钩子方法:子类可重写以定制伤害获取逻辑
func update_attack() -> void:
if damage:
damage.randomize_damage()
## 钩子方法:子类可重写以返回正确的攻击者位置
func get_attacker_position() -> Vector2:
return global_position
## 通用逻辑在基类实现,调用钩子方法
func _on_hitbox_area_entered_(area: Area2D) -> void:
update_attack()
if area is Hurtbox:
area.take_damage(damage, get_attacker_position())
gdscript
# 子类 - 只重写钩子方法
class_name PlayerHitbox
extends Hitbox
@onready var player: Hahashin = get_owner()
## 重写:从 CombatComponent 获取伤害
func update_attack() -> void:
damage = player.combat_component.current_damage
## 重写:返回玩家位置
func get_attacker_position() -> Vector2:
return player.global_position
架构检查要点
- •通用性:是否使用
@export配置化?能否跨场景复用? - •模块化:是否单一职责?是否用信号解耦?
- •可复用性:是否有清晰接口?Resource 类是否正确使用?
- •简洁性:是否避免过度设计?代码是否自解释?
- •继承设计:基类是否提供钩子方法?子类是否只重写必要方法?
- •信号连接:子类是否重复连接了基类已连接的信号?是否遗漏
super()调用?