# 模块开发指南

本文档详细说明如何在 Whale Town 项目中开发新的游戏模块。

## 🎯 模块设计原则

### 核心原则
1. **单一职责** - 每个模块只负责一个特定的游戏功能
2. **高内聚低耦合** - 模块内部紧密相关，模块间松散耦合
3. **可复用性** - 模块应该能在不同场景中复用
4. **标准化接口** - 统一的模块接口和通信方式
5. **测试友好** - 模块应该易于测试和调试

### 模块分类
- **UI模块** - 用户界面组件和交互逻辑
- **游戏逻辑模块** - 角色、战斗、对话等核心功能
- **系统模块** - 存档、设置、网络等系统功能
- **工具模块** - 通用工具和辅助功能

## 🏗️ 模块结构

### 标准目录结构
```
module/YourModule/
├── YourModule.gd           # 主模块脚本
├── components/             # 子组件
│   ├── Component1.gd
│   └── Component2.gd
├── data/                   # 模块数据
│   ├── module_config.json
│   └── default_data.json
├── scenes/                 # 模块场景
│   ├── YourModule.tscn
│   └── components/
├── tests/                  # 模块测试
│   ├── test_your_module.gd
│   └── test_components.gd
└── README.md              # 模块文档
```

### 文件命名规范
- **主模块脚本**: `ModuleName.gd` (PascalCase)
- **组件脚本**: `ComponentName.gd` (PascalCase)
- **场景文件**: `module_name.tscn` (snake_case)
- **数据文件**: `snake_case.json`
- **测试文件**: `test_module_name.gd`

## 📝 模块开发步骤

### 第一步：创建模块结构

```bash
# 创建模块目录
mkdir module/YourModule
cd module/YourModule

# 创建子目录
mkdir components data scenes tests

# 创建主要文件
touch YourModule.gd
touch README.md
touch data/module_config.json
```

### 第二步：实现模块接口

每个模块都应该实现标准的模块接口：

```gdscript
# YourModule.gd
extends Node
class_name YourModule

# 模块信息
const MODULE_NAME = "YourModule"
const MODULE_VERSION = "1.0.0"
const MODULE_AUTHOR = "Your Name"

# 模块状态
enum ModuleState {
	UNINITIALIZED,
	INITIALIZING,
	READY,
	ERROR
}

var current_state: ModuleState = ModuleState.UNINITIALIZED
var config: Dictionary = {}
var is_enabled: bool = true

# 必需接口方法
func initialize() -> bool:
	"""初始化模块"""
	current_state = ModuleState.INITIALIZING
	
	# 加载配置
	if not _load_config():
		current_state = ModuleState.ERROR
		return false
	
	# 初始化组件
	if not _initialize_components():
		current_state = ModuleState.ERROR
		return false
	
	# 注册事件监听
	_register_events()
	
	current_state = ModuleState.READY
	return true

func cleanup():
	"""清理模块资源"""
	_unregister_events()
	_cleanup_components()
	current_state = ModuleState.UNINITIALIZED

func get_module_info() -> Dictionary:
	"""获取模块信息"""
	return {
		"name": MODULE_NAME,
		"version": MODULE_VERSION,
		"author": MODULE_AUTHOR,
		"state": current_state,
		"enabled": is_enabled
	}

# 私有方法
func _load_config() -> bool:
	"""加载模块配置"""
	var config_path = "res://module/%s/data/module_config.json" % MODULE_NAME
	if not FileAccess.file_exists(config_path):
		print("警告: 模块配置文件不存在: ", config_path)
		return true  # 使用默认配置
	
	var file = FileAccess.open(config_path, FileAccess.READ)
	if file == null:
		print("错误: 无法读取配置文件: ", config_path)
		return false
	
	var json_string = file.get_as_text()
	file.close()
	
	var json = JSON.new()
	var parse_result = json.parse(json_string)
	if parse_result != OK:
		print("错误: 配置文件JSON格式错误: ", config_path)
		return false
	
	config = json.data
	return true

func _initialize_components() -> bool:
	"""初始化子组件"""
	# 在这里初始化模块的子组件
	return true

func _cleanup_components():
	"""清理子组件"""
	# 在这里清理模块的子组件
	pass

func _register_events():
	"""注册事件监听"""
	# 使用EventSystem注册需要监听的事件
	# EventSystem.connect_event("event_name", _on_event_handler)
	pass

func _unregister_events():
	"""取消事件监听"""
	# 取消所有事件监听
	# EventSystem.disconnect_event("event_name", _on_event_handler)
	pass
```

### 第三步：创建模块配置

```json
// data/module_config.json
{
  "module_name": "YourModule",
  "version": "1.0.0",
  "enabled": true,
  "dependencies": [],
  "settings": {
    "auto_initialize": true,
    "debug_mode": false
  },
  "resources": {
    "textures": [],
    "sounds": [],
    "data_files": []
  }
}
```

### 第四步：实现具体功能

根据模块类型实现具体功能：

#### UI模块示例
```gdscript
# UI模块应该继承Control或其子类
extends Control
class_name UIModule

signal ui_event_triggered(event_name: String, data: Dictionary)

func show_ui():
	"""显示UI"""
	visible = true
	# 播放显示动画
	_play_show_animation()

func hide_ui():
	"""隐藏UI"""
	# 播放隐藏动画
	_play_hide_animation()
	await get_tree().create_timer(0.3).timeout
	visible = false

func _play_show_animation():
	"""播放显示动画"""
	var tween = create_tween()
	modulate.a = 0.0
	tween.tween_property(self, "modulate:a", 1.0, 0.3)

func _play_hide_animation():
	"""播放隐藏动画"""
	var tween = create_tween()
	tween.tween_property(self, "modulate:a", 0.0, 0.3)
```

#### 游戏逻辑模块示例
```gdscript
# 游戏逻辑模块
extends Node
class_name GameLogicModule

signal state_changed(old_state: String, new_state: String)
signal data_updated(data_type: String, new_data: Dictionary)

var module_data: Dictionary = {}
var current_state: String = "idle"

func process_game_logic(delta: float):
	"""处理游戏逻辑"""
	match current_state:
		"idle":
			_process_idle_state(delta)
		"active":
			_process_active_state(delta)
		"paused":
			_process_paused_state(delta)

func change_state(new_state: String):
	"""改变模块状态"""
	var old_state = current_state
	current_state = new_state
	state_changed.emit(old_state, new_state)

func update_data(data_type: String, new_data: Dictionary):
	"""更新模块数据"""
	module_data[data_type] = new_data
	data_updated.emit(data_type, new_data)
```

### 第五步：添加测试

```gdscript
# tests/test_your_module.gd
extends "res://addons/gut/test.gd"

var module: YourModule

func before_each():
	module = YourModule.new()
	add_child(module)

func after_each():
	module.queue_free()

func test_module_initialization():
	assert_true(module.initialize(), "模块应该能够正确初始化")
	assert_eq(module.current_state, YourModule.ModuleState.READY, "初始化后状态应该为READY")

func test_module_cleanup():
	module.initialize()
	module.cleanup()
	assert_eq(module.current_state, YourModule.ModuleState.UNINITIALIZED, "清理后状态应该为UNINITIALIZED")

func test_module_info():
	var info = module.get_module_info()
	assert_true(info.has("name"), "模块信息应该包含名称")
	assert_true(info.has("version"), "模块信息应该包含版本")
	assert_eq(info.name, "YourModule", "模块名称应该正确")
```

### 第六步：编写文档

```markdown
# YourModule 模块

## 功能描述
简要描述模块的主要功能和用途。

## 使用方法
```gdscript
# 创建和初始化模块
var your_module = YourModule.new()
add_child(your_module)
your_module.initialize()

# 使用模块功能
your_module.some_function()
```

## API参考
### 公共方法
- `initialize() -> bool` - 初始化模块
- `cleanup()` - 清理模块资源
- `get_module_info() -> Dictionary` - 获取模块信息

### 信号
- `signal_name(param: Type)` - 信号描述

## 配置选项
描述模块的配置选项和默认值。

## 依赖关系
列出模块的依赖项。

## 注意事项
使用模块时需要注意的事项。
```

## 🔧 模块集成

### 在场景中使用模块

```gdscript
# 在场景脚本中使用模块
extends Control

var inventory_module: InventoryModule
var dialogue_module: DialogueModule

func _ready():
	# 创建并初始化模块
	inventory_module = InventoryModule.new()
	add_child(inventory_module)
	inventory_module.initialize()
	
	dialogue_module = DialogueModule.new()
	add_child(dialogue_module)
	dialogue_module.initialize()
	
	# 连接模块事件
	inventory_module.item_selected.connect(_on_item_selected)
	dialogue_module.dialogue_finished.connect(_on_dialogue_finished)

func _on_item_selected(item_data: Dictionary):
	print("选中物品: ", item_data.name)

func _on_dialogue_finished():
	print("对话结束")
```

### 模块间通信

推荐使用EventSystem进行模块间通信：

```gdscript
# 发送事件
EventSystem.emit_event("inventory_item_used", {
	"item_id": "potion_001",
	"quantity": 1
})

# 监听事件
EventSystem.connect_event("inventory_item_used", _on_item_used)

func _on_item_used(data: Dictionary):
	print("使用了物品: ", data.item_id)
```

## 🧪 测试和调试

### 单元测试
每个模块都应该有对应的单元测试：

```bash
# 运行模块测试
godot --headless --script tests/test_your_module.gd
```

### 调试技巧
1. **使用print语句** - 在关键位置添加调试输出
2. **断点调试** - 在Godot编辑器中设置断点
3. **状态监控** - 实时监控模块状态变化
4. **事件追踪** - 记录事件的发送和接收

### 性能监控
```gdscript
# 性能监控示例
func _process(delta):
	var start_time = Time.get_time_dict_from_system()
	
	# 执行模块逻辑
	process_module_logic(delta)
	
	var end_time = Time.get_time_dict_from_system()
	var execution_time = (end_time.hour * 3600 + end_time.minute * 60 + end_time.second) - \
						(start_time.hour * 3600 + start_time.minute * 60 + start_time.second)
	
	if execution_time > 0.016:  # 超过16ms
		print("警告: 模块执行时间过长: ", execution_time, "秒")
```

## 📚 最佳实践

### 代码质量
1. **遵循命名规范** - 使用清晰、一致的命名
2. **添加详细注释** - 解释复杂逻辑和设计决策
3. **错误处理** - 妥善处理各种异常情况
4. **资源管理** - 及时释放不需要的资源

### 性能优化
1. **避免频繁的内存分配** - 重用对象和数据结构
2. **合理使用信号** - 避免过多的信号连接
3. **批量处理** - 将多个操作合并处理
4. **延迟加载** - 按需加载资源和数据

### 可维护性
1. **模块化设计** - 保持模块的独立性
2. **版本控制** - 记录模块的版本变化
3. **文档更新** - 及时更新模块文档
4. **向后兼容** - 考虑API的向后兼容性

## 🔍 常见问题

### Q: 如何处理模块依赖？
A: 在模块配置中声明依赖，在初始化时检查依赖是否满足。

### Q: 模块间如何共享数据？
A: 使用EventSystem传递数据，或通过GameManager等全局管理器。

### Q: 如何调试模块问题？
A: 使用Godot的调试工具，添加日志输出，编写单元测试。

### Q: 模块性能如何优化？
A: 避免在_process中执行重复计算，使用对象池，合理管理资源。

## 📖 参考资料

- [Godot官方文档](https://docs.godotengine.org/)
- [项目命名规范](./naming_convention.md)
- [代码注释规范](./code_comment_guide.md)
- [Git提交规范](./git_commit_guide.md)

---

**记住：好的模块设计是项目成功的关键！**