场景模板:battle_data
基于这个战斗场景元模板(BattleData),可以自定义以下战斗场景的各个方面:
🎯 基础信息配置
- 战斗标题 ( battle_title ) – 设置战斗的名称
- 战斗描述 ( battle_description ) – 多行文本描述,用于战斗日志或介绍
🎨 视觉与音频
- 战斗背景 ( battle_background ) – 设置战斗场景的背景图片(Texture2D)
- 战斗音乐 ( battle_music ) – 设置战斗时的背景音乐(AudioStream)
👥 角色配置
- 敌人数据列表 ( enemy_data_list ) – 字典结构,键为CharacterData(角色数据),值为Vector2(战场位置)
- 玩家角色数据列表 ( player_data_list ) – 可选,如果为空则使用全局玩家队伍,同样包含角色数据和位置
⏱️ 战斗规则
- 最大回合数 ( max_turn_count ) – 设置战斗的最大回合数,超过自动失败(0表示无限制)
- 是否允许逃跑 ( allow_escape ) – 控制玩家是否可以逃跑
🏆 战斗结果
- 胜利场景 ( victory_scene ) – 战斗胜利后跳转的场景文件(.tscn)
- 失败场景 ( defeat_scene ) – 战斗失败后跳转的场景文件(.tscn)
💰 奖励系统
- 经验奖励 ( exp_reward ) – 战斗胜利后获得的经验值
- 金币奖励 ( gold_reward ) – 战斗胜利后获得的金币数量
- 物品奖励 ( item_rewards ) – 数组,包含战斗胜利后获得的物品
🎪 特殊战斗设置
- Boss战标识 ( is_boss_battle ) – 标记是否为Boss战斗
- 特殊条件 ( special_conditions ) – 字典结构,可以存储自定义的特殊战斗条件
🔧 实用功能
- 获取敌人数量 ( get_enemy_count() ) – 方法,返回敌人数量
- 获取玩家数量 ( get_player_count() ) – 方法,返回玩家角色数量
- 数据有效性检查 ( is_valid() ) – 方法,检查战斗数据是否有效(至少需要敌人数据)
**总结一下 `main.gd` 的作用**:它就像一个启动器。当 `Main` 节点准备就绪时,它会创建并显示战斗场景,然后使用在编辑器里配置好的战斗数据来初始化这个场景。
接下来,为了完整地理解整个初始化流程,我们需要查看 `BattleScene` 和 `BattleData` 相关的脚本。我现在就来查找并分析这些脚本。
好的,我已经分析了 `battle_scene.gd` 和 `battle_data.gd` 的代码。现在,我们可以将所有信息串联起来,完整地了解一个战斗场景是如何被初始化的。
整个流程可以分为三个主要部分:**数据准备**、**场景加载** 和 **场景初始化**。
### 1. 数据准备 (`battle_data.gd`)
首先,我们来看 `d:\Desktop\Godot\course\43最终打磨\scripts\resources\battle_data.gd`。
gdscript
extends Resource
class_name BattleData
战斗标题
@export var battle_title: String = “战斗”
战斗背景
@export var battle_background: Texture2D
战斗音乐
@export var battle_music: AudioStream
敌人数据列表
@export var enemy_data_list: Dictionary[CharacterData, Vector2] = {}
玩家角色数据列表
@export var player_data_list: Dictionary[CharacterData, Vector2] = {}
… 其他战斗相关数据
这个脚本定义了一个 `BattleData` 资源。在 Godot 中,`Resource` 是一种纯粹的数据容器,非常适合用来存储配置信息。
- **`@export`**: 你会看到大量的 `@export` 关键字。这意味着你可以在 Godot 编辑器的“检查器”面板中,像填写表单一样,为一场战斗配置所有需要的数据,而无需修改任何代码。
- **核心数据**: 对于场景初始化来说,最重要的两个属性是:
* `player_data_list`: 一个字典,存储了所有**玩家角色**的数据 (`CharacterData`) 以及他们在场景中的初始**位置** (`Vector2`)。
* `enemy_data_list`: 与上面类似,但用于存储**敌人角色**的数据和位置。
- **其他数据**: 还包括战斗的背景音乐 (`battle_music`)、标题、胜利/失败条件等。
所以,在战斗开始前,开发者会先创建一个 `BattleData` 资源文件,并在编辑器里填好这场战斗的所有细节。
### 2. 场景加载 (`main.gd`)
接下来是 `d:\Desktop\Godot\course\43最终打磨\main.gd`,它是整个流程的起点。
gdscript
extends Node2D
class_name Main
const BATTLE_SCENE = preload(“res://scenes/battle/battle_scene.tscn”)
@export var battle_data : BattleData
func _ready() -> void:
var battle_scene : BattleScene = BATTLE_SCENE.instantiate()
add_child(battle_scene)
battle_scene.initialize_battle(battle_data)
`main.gd` 的作用非常直接:
1. **持有数据**: 它有一个 `@export var battle_data : BattleData` 成员。这意味着你可以在主场景中选中挂载了 `main.gd` 的节点,然后将我们第一步中创建的 `BattleData` 资源文件拖拽到这个变量上。
2. **实例化场景**: 在 `_ready` 函数(当节点准备就绪时自动执行)中,它实例化了预加载的战斗场景 `battle_scene.tscn`。
3. **传递数据**: 最关键的一步是,它调用了新建战斗场景实例的 `initialize_battle` 方法,并将持有的 `battle_data` 作为参数传递了过去。
### 3. 场景初始化 (`battle_scene.gd`)
最后,我们来看 `d:\Desktop\Godot\course\43最终打磨\scenes\battle\battle_scene.gd` 中的 `initialize_battle` 函数,这是初始化的核心。
gdscript
func initialize_battle(battle_data: BattleData) -> void:
# 1. 清理旧角色 (如果有的话)
for player in player_area.get_children():
player.queue_free()
for enemy in enemy_area.get_children():
enemy.queue_free()
# 2. 根据数据生成玩家角色
for player_data in battle_data.player_data_list:
var pos : Vector2 = battle_data.player_data_list[player_data]
var player: Character = _spawn_character(player_data, pos)
player_area.add_child(player)
battle_manager.add_character(player, true)
# 3. 根据数据生成敌人角色
for enemy_data in battle_data.enemy_data_list:
var pos : Vector2 = battle_data.enemy_data_list[enemy_data]
var enemy: Character = _spawn_character(enemy_data, pos)
enemy.is_player = false
enemy_area.add_child(enemy)
battle_manager.add_character(enemy, false)
# 4. 设置音乐并播放
stream_player.stream = battle_data.battle_music
stream_player.play()
# 5. 连接信号并开始战斗
_connect_character_click_signals()
battle_manager.start_battle()
“`
这个函数接收到 battle_data 后,执行了以下一系列操作:
- 清场: 首先,它会清空
player_area和enemy_area两个区域,确保不会有上一场战斗的角色残留。 - 生成玩家: 遍历
battle_data中的player_data_list。对列表中的每一个player_data:- 调用
_spawn_character函数,这个函数会创建一个通用的Character场景实例。 - 将
player_data(包含角色的名字、属性、技能等) 赋值给这个新创建的Character实例。 - 设置角色的位置。
- 将角色添加到
player_area节点下,使其显示在屏幕的玩家区域。 - 将角色注册到
battle_manager(战斗管理器)中,并标记为玩家单位。
- 调用
- 生成敌人: 重复与生成玩家几乎完全相同的步骤,但这次是遍历
enemy_data_list,并将角色添加到enemy_area。 - 设置音乐: 从
battle_data中读取战斗音乐并开始播放。 - 开始战斗: 最后,调用
battle_manager.start_battle(),这会启动战斗的逻辑,比如决定哪个角色先行动。
总结
整个初始化流程是一个清晰的、数据驱动的设计模式:
编辑器配置 -> main.gd 读取配置并加载场景 -> battle_scene.gd 接收配置并动态构建场景
这种方式的好处是高度灵活。如果你想创建一场新的战斗,你不需要修改任何代码,只需要:
- 创建一个新的
CharacterData资源来定义新敌人。 - 创建一个新的
BattleData资源,在里面配置好敌人列表、玩家列表和音乐等。 - 在主场景中,将这个新的
BattleData资源赋给Main节点的battle_data变量。
