Files
whale-town-front/docs/02-开发规范/架构与通信规范.md
moyin 1ff677b3b2 docs: 重新组织文档结构,按开发阶段分类
新的目录结构:
  01-项目入门/     # 新人必读,项目基础
  02-开发规范/     # 编码标准和规范
  03-技术实现/     # 具体开发指导
  04-高级开发/     # 进阶开发技巧
  05-部署运维/     # 发布和部署
  06-功能模块/     # 特定功能文档

 新增导航文档:
- docs/README.md - 完整的文档导航和使用指南
- 各目录下的README.md - 分类说明和使用指导

 优化效果:
- 开发者可以按阶段快速定位需要的文档
- 新人有清晰的学习路径
- 不同角色有针对性的文档推荐
- 提供了问题导向的快速查找功能
2025-12-31 18:02:16 +08:00

272 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 架构与通信规范
本文档定义了WhaleTown项目的架构设计原则和组件间通信规范。
## 🏛️ 架构设计原则
### 核心原则
- **"信号向上,调用向下"** - 父节点调用子节点方法,子节点发出信号通知父节点
- **高度解耦** - 通过事件系统实现组件间通信,避免直接依赖
- **分层架构** - 严格的三层架构:框架层、游戏层、界面层
- **单一职责** - 每个组件只负责一个明确的功能
### 分层架构详解
```
┌─────────────────────────────────────┐
│ UI Layer (界面层) │
│ UI/Windows/, UI/HUD/ │
├─────────────────────────────────────┤
│ Scenes Layer (游戏层) │
│ Scenes/Maps/, Scenes/Entities/ │
├─────────────────────────────────────┤
│ _Core Layer (框架层) │
│ _Core/managers/, _Core/systems/ │
└─────────────────────────────────────┘
```
## 🔄 事件系统 (EventSystem)
### 事件系统位置
- **文件路径**: `_Core/systems/EventSystem.gd`
- **自动加载**: 必须设置为AutoLoad单例
- **作用**: 全局事件总线,实现跨模块通信
### 事件命名规范
所有事件名称必须在 `_Core/EventNames.gd` 中定义:
```gdscript
# _Core/EventNames.gd
class_name EventNames
# 玩家相关事件
const PLAYER_MOVED = "player_moved"
const PLAYER_HEALTH_CHANGED = "player_health_changed"
const PLAYER_DIED = "player_died"
# 交互事件
const INTERACT_PRESSED = "interact_pressed"
const NPC_TALKED = "npc_talked"
const ITEM_COLLECTED = "item_collected"
# UI事件
const UI_BUTTON_CLICKED = "ui_button_clicked"
const DIALOG_OPENED = "dialog_opened"
const DIALOG_CLOSED = "dialog_closed"
# 游戏状态事件
const GAME_PAUSED = "game_paused"
const GAME_RESUMED = "game_resumed"
const SCENE_CHANGED = "scene_changed"
```
### 事件使用方法
#### 发送事件
```gdscript
# 发送简单事件
EventSystem.emit_event(EventNames.PLAYER_MOVED)
# 发送带数据的事件
EventSystem.emit_event(EventNames.PLAYER_HEALTH_CHANGED, {
"old_health": 80,
"new_health": 60,
"damage": 20
})
```
#### 监听事件
```gdscript
func _ready() -> void:
# 连接事件监听
EventSystem.connect_event(EventNames.PLAYER_DIED, _on_player_died)
EventSystem.connect_event(EventNames.ITEM_COLLECTED, _on_item_collected)
func _on_player_died(data: Dictionary = {}) -> void:
print("玩家死亡,游戏结束")
# 处理玩家死亡逻辑
func _on_item_collected(data: Dictionary) -> void:
var item_name = data.get("item_name", "未知物品")
print("收集到物品: ", item_name)
```
#### 断开事件监听
```gdscript
func _exit_tree() -> void:
# 节点销毁时断开事件监听
EventSystem.disconnect_event(EventNames.PLAYER_DIED, _on_player_died)
EventSystem.disconnect_event(EventNames.ITEM_COLLECTED, _on_item_collected)
```
## 🎯 单例管理器
### 允许的自动加载单例
项目中只允许以下三个单例:
1. **GameManager** - 游戏状态管理
- 路径: `_Core/managers/GameManager.gd`
- 职责: 游戏状态、场景数据、全局配置
2. **SceneManager** - 场景管理
- 路径: `_Core/managers/SceneManager.gd`
- 职责: 场景切换、场景生命周期
3. **EventSystem** - 事件系统
- 路径: `_Core/systems/EventSystem.gd`
- 职责: 全局事件通信
### 单例使用规范
```gdscript
# ✅ 正确:高层组件可以访问单例
func _ready() -> void:
var current_scene = SceneManager.get_current_scene()
var game_state = GameManager.get_game_state()
# ❌ 错误底层实体不应直接访问GameManager
# 在Player.gd或NPC.gd中避免这样做
func _ready() -> void:
GameManager.register_player(self) # 不推荐
# ✅ 正确:使用事件系统
func _ready() -> void:
EventSystem.emit_event(EventNames.PLAYER_SPAWNED, {"player": self})
```
## 🔗 组件通信模式
### 1. 父子通信
```gdscript
# 父节点调用子节点方法(向下调用)
func _on_button_pressed() -> void:
child_component.activate()
child_component.set_data(some_data)
# 子节点发出信号通知父节点(向上信号)
# 在子节点中:
signal component_activated(data: Dictionary)
signal component_finished()
func _some_action() -> void:
component_activated.emit({"status": "active"})
```
### 2. 兄弟组件通信
```gdscript
# 通过共同的父节点中转
# 或使用事件系统
func _notify_sibling() -> void:
EventSystem.emit_event(EventNames.COMPONENT_MESSAGE, {
"sender": self,
"message": "Hello sibling!"
})
```
### 3. 跨场景通信
```gdscript
# 使用事件系统进行跨场景通信
func _change_scene_with_data() -> void:
EventSystem.emit_event(EventNames.SCENE_DATA_TRANSFER, {
"target_scene": "battle_scene",
"player_data": player_data
})
```
## 🚫 禁止的通信模式
### 1. 直接节点引用
```gdscript
# ❌ 错误:直接获取其他场景的节点
func _bad_communication() -> void:
var other_scene = get_tree().get_first_node_in_group("other_scene")
other_scene.do_something() # 强耦合,难以维护
```
### 2. 全局变量传递
```gdscript
# ❌ 错误:使用全局变量传递状态
# 在autoload中
var global_player_data = {} # 避免这种做法
```
### 3. 循环依赖
```gdscript
# ❌ 错误A依赖BB又依赖A
# ComponentA.gd
var component_b: ComponentB
# ComponentB.gd
var component_a: ComponentA # 循环依赖
```
## 📋 通信最佳实践
### 1. 事件数据结构
```gdscript
# 使用结构化的事件数据
EventSystem.emit_event(EventNames.PLAYER_ATTACK, {
"attacker": self,
"target": target_enemy,
"damage": damage_amount,
"attack_type": "melee",
"timestamp": Time.get_time_dict_from_system()
})
```
### 2. 错误处理
```gdscript
func _on_event_received(data: Dictionary) -> void:
# 验证数据完整性
if not data.has("required_field"):
push_error("事件数据缺少必需字段: required_field")
return
# 安全地获取数据
var value = data.get("optional_field", default_value)
```
### 3. 性能考虑
```gdscript
# 避免在_process中频繁发送事件
var last_position: Vector2
func _process(delta: float) -> void:
if global_position.distance_to(last_position) > 10.0:
EventSystem.emit_event(EventNames.PLAYER_MOVED, {
"position": global_position
})
last_position = global_position
```
## 🧪 测试通信系统
### 单元测试示例
```gdscript
extends GutTest
func test_event_emission():
# 监听事件
watch_signals(EventSystem)
# 发送事件
EventSystem.emit_event(EventNames.PLAYER_MOVED, {"x": 100, "y": 200})
# 验证事件发送
assert_signal_emitted(EventSystem, "event_raised")
func test_event_data():
var received_data: Dictionary
# 连接事件监听
EventSystem.connect_event(EventNames.TEST_EVENT, func(data): received_data = data)
# 发送测试数据
var test_data = {"test": "value"}
EventSystem.emit_event(EventNames.TEST_EVENT, test_data)
# 验证数据传递
assert_eq(received_data, test_data)
```
---
**记住:良好的架构设计是项目成功的基石!遵循这些通信规范可以确保代码的可维护性和扩展性。**