2. 项目搭建
2026/4/14大约 12 分钟
2. 伏魔记——项目搭建
2.1 什么是项目搭建?
想象你要开一家餐厅。在接待第一位客人之前,你需要租场地、装修厨房、采购厨具、招聘厨师。项目搭建就是给我们的RPG游戏做这些"开张前的准备工作"。
在Godot中搭建一个RPG项目,我们需要做好四件事:
- 创建项目:在Godot中新建游戏工程
- 规划目录:把脚本、场景、素材分门别类放好
- 创建GameManager:搭建全局管理器,统筹所有子系统
- 定义数据结构:设计角色、物品、技能等数据的存储格式
2.2 创建Godot项目
第一步:新建项目
- 打开Godot 4.x引擎
- 点击"新建项目"(New Project)
- 项目名称填写:
FuMoJi - 选择渲染模式:2D
- 选择一个你喜欢的项目保存路径
- 点击"创建并编辑"(Create & Edit)
第二步:配置项目参数
打开菜单 项目 → 项目设置(Project → Project Settings),进行以下配置:
| 设置项 | 值 | 说明 |
|---|---|---|
| 应用程序 → 名称 | 伏魔记 | 游戏显示名称 |
| 显示 → 窗口 → 宽度 | 960 | RPG需要较大的画面 |
| 显示 → 窗口 → 高度 | 640 | 16:10的经典比例 |
| 显示 → 窗口 → 不可拉伸 | 勾选 | 固定窗口大小 |
| 输入 → 键盘映射 | 见下方 | 添加RPG操作按键 |
第三步:配置输入映射
RPG的操作比俄罗斯方块多一些:
| 动作名称 | 按键 | 说明 |
|---|---|---|
move_up | 上方向键、W | 角色向上移动 |
move_down | 下方向键、S | 角色向下移动 |
move_left | 左方向键、A | 角色向左移动 |
move_right | 右方向键、D | 角色向右移动 |
confirm | 空格、Enter | 确认/交互 |
cancel | Esc、Z | 取消/返回 |
menu | Esc、M | 打开游戏菜单 |
attack | 空格 | 战斗中选择攻击 |
skill | Q | 战斗中选择技能 |
item | E | 战斗中选择物品 |
defend | R | 战斗中选择防御 |
2.3 目录结构规划
RPG的文件比俄罗斯方块多很多,需要好好规划:
res:// ← 项目根目录
├── scenes/ ← 场景文件夹
│ ├── main.tscn ← 主场景(游戏入口)
│ ├── player/ ← 玩家相关场景
│ │ ├── player.tscn ← 玩家角色
│ │ └── player_battle.tscn ← 战斗中的玩家
│ ├── maps/ ← 地图场景
│ │ ├── town_main.tscn ← 主城
│ │ ├── dungeon_forest.tscn ← 森林地下城
│ │ └── dungeon_cave.tscn ← 洞穴地下城
│ ├── battle/ ← 战斗场景
│ │ ├── battle_scene.tscn ← 战斗主场景
│ │ └── battle_ui.tscn ← 战斗UI
│ ├── npcs/ ← NPC场景
│ │ ├── npc_base.tscn ← NPC基础场景
│ │ └── shop_npc.tscn ← 商店NPC
│ └── ui/ ← UI场景
│ ├── main_menu.tscn ← 主菜单
│ ├── dialogue_box.tscn ← 对话框
│ ├── inventory_ui.tscn ← 背包界面
│ ├── status_panel.tscn ← 角色状态面板
│ ├── quest_log.tscn ← 任务日志
│ ├── shop_ui.tscn ← 商店界面
│ ├── save_load_ui.tscn ← 存档/读档界面
│ └── battle_result.tscn ← 战斗结算
├── scripts/ ← 脚本文件夹
│ ├── managers/ ← 管理器脚本
│ │ ├── game_manager.gd/.cs ← 游戏总管理器
│ │ ├── scene_manager.gd/.cs ← 场景切换管理器
│ │ ├── party_manager.gd/.cs ← 队伍管理器
│ │ ├── inventory_manager.gd/.cs ← 背包管理器
│ │ └── quest_manager.gd/.cs ← 任务管理器
│ ├── battle/ ← 战斗系统脚本
│ │ ├── battle_manager.gd/.cs ← 战斗管理器
│ │ ├── battle_unit.gd/.cs ← 战斗单位
│ │ └── enemy_ai.gd/.cs ← 敌人AI
│ ├── dialogue/ ← 对话系统脚本
│ │ ├── dialogue_manager.gd/.cs ← 对话管理器
│ │ └── dialogue_data.gd/.cs ← 对话数据
│ ├── player/ ← 玩家脚本
│ │ └── player_controller.gd/.cs ← 玩家控制器
│ └── data/ ← 数据定义脚本
│ ├── character_stats.gd/.cs ← 角色属性
│ ├── item_data.gd/.cs ← 物品数据
│ ├── skill_data.gd/.cs ← 技能数据
│ └── constants.gd/.cs ← 常量定义
├── data/ ← 游戏数据文件夹
│ ├── characters/ ← 角色数据(JSON)
│ ├── items/ ← 物品数据(JSON)
│ ├── skills/ ← 技能数据(JSON)
│ ├── enemies/ ← 敌人数据(JSON)
│ ├── quests/ ← 任务数据(JSON)
│ └── dialogues/ ← 对话数据(JSON)
├── assets/ ← 素材文件夹
│ ├── sprites/ ← 精灵图
│ │ ├── characters/ ← 角色精灵
│ │ ├── enemies/ ← 敌人精灵
│ │ ├── tiles/ ← 瓦片素材
│ │ └── ui/ ← UI精灵
│ ├── fonts/ ← 字体
│ └── audio/ ← 音频
│ ├── music/ ← 背景音乐
│ └── sfx/ ← 音效
└── autoload/ ← 自动加载
└── game_manager.gd/.cs ← 全局游戏管理器2.4 常量定义
RPG中有很多固定数值,比如角色初始属性、背包大小上限等,我们把它们集中管理。
C
/// <summary>
/// 伏魔记游戏常量
/// </summary>
public static class RpgConstants
{
// ===== 窗口与渲染 =====
/// <summary>游戏窗口宽度</summary>
public const int WindowWidth = 960;
/// <summary>游戏窗口高度</summary>
public const int WindowHeight = 640;
/// <summary>每个瓦片的像素大小</summary>
public const int TileSize = 32;
/// <summary>角色移动速度(像素/秒)</summary>
public const int PlayerSpeed = 120;
// ===== 角色属性 =====
/// <summary>初始最大HP</summary>
public const int BaseMaxHp = 100;
/// <summary>初始最大MP</summary>
public const int BaseMaxMp = 30;
/// <summary>初始攻击力</summary>
public const int BaseAttack = 15;
/// <summary>初始防御力</summary>
public const int BaseDefense = 8;
/// <summary>初始速度</summary>
public const int BaseSpeed = 10;
/// <summary>角色最大等级</summary>
public const int MaxLevel = 99;
/// <summary>队伍最大人数</summary>
public const int MaxPartySize = 4;
// ===== 升级 =====
/// <summary>1级升2级所需经验</summary>
public const int BaseExpRequired = 50;
/// <summary>每升一级额外增加的经验需求</summary>
public const int ExpIncreasePerLevel = 30;
// ===== 背包 =====
/// <summary>背包最大格子数</summary>
public const int InventoryMaxSlots = 20;
/// <summary>每种消耗品最大堆叠数量</summary>
public const int MaxStackCount = 99;
// ===== 战斗 =====
/// <summary>战斗中每方最大单位数</summary>
public const int MaxBattleUnits = 4;
/// <summary>防御时减伤比例(50%)</summary>
public const float DefendDamageReduction = 0.5f;
// ===== 地下城 =====
/// <summary>随机遭遇战的步数间隔</summary>
public const int EncounterStepInterval = 15;
// ===== 存档 =====
/// <summary>最大存档槽位数</summary>
public const int MaxSaveSlots = 3;
// ===== 对话 =====
/// <summary>每行文字的显示速度(秒/字)</summary>
public const float TextSpeed = 0.05f;
}GDScript
## 伏魔记游戏常量
class_name RpgConstants
# ===== 窗口与渲染 =====
## 游戏窗口宽度
const WINDOW_WIDTH: int = 960
## 游戏窗口高度
const WINDOW_HEIGHT: int = 640
## 每个瓦片的像素大小
const TILE_SIZE: int = 32
## 角色移动速度(像素/秒)
const PLAYER_SPEED: int = 120
# ===== 角色属性 =====
## 初始最大HP
const BASE_MAX_HP: int = 100
## 初始最大MP
const BASE_MAX_MP: int = 30
## 初始攻击力
const BASE_ATTACK: int = 15
## 初始防御力
const BASE_DEFENSE: int = 8
## 初始速度
const BASE_SPEED: int = 10
## 角色最大等级
const MAX_LEVEL: int = 99
## 队伍最大人数
const MAX_PARTY_SIZE: int = 4
# ===== 升级 =====
## 1级升2级所需经验
const BASE_EXP_REQUIRED: int = 50
## 每升一级额外增加的经验需求
const EXP_INCREASE_PER_LEVEL: int = 30
# ===== 背包 =====
## 背包最大格子数
const INVENTORY_MAX_SLOTS: int = 20
## 每种消耗品最大堆叠数量
const MAX_STACK_COUNT: int = 99
# ===== 战斗 =====
## 战斗中每方最大单位数
const MAX_BATTLE_UNITS: int = 4
## 防御时减伤比例(50%)
const DEFEND_DAMAGE_REDUCTION: float = 0.5
# ===== 地下城 =====
## 随机遭遇战的步数间隔
const ENCOUNTER_STEP_INTERVAL: int = 15
# ===== 存档 =====
## 最大存档槽位数
const MAX_SAVE_SLOTS: int = 3
# ===== 对话 =====
## 每行文字的显示速度(秒/字)
const TEXT_SPEED: float = 0.052.5 GameManager——全局游戏管理器
GameManager 是整个RPG的"总指挥",就像一个公司的CEO,所有子系统都要向它汇报。它管理着玩家的队伍、背包、任务进度、当前游戏状态等核心数据。
配置自动加载
- 菜单栏 → 项目 → 项目设置 → 自动加载 标签页
- 选择
scripts/managers/game_manager.gd(或.cs) - 名称填写
GameManager - 点击"添加"
GameManager脚本
C
using Godot;
using System.Collections.Generic;
/// <summary>
/// 伏魔记全局游戏管理器
/// 统筹队伍、背包、任务、场景切换等所有子系统
/// </summary>
public partial class GameManager : Node
{
// ===== 信号 =====
[Signal] public delegate void GameStateChangedEventHandler(RpgGameState newState);
[Signal] public delegate void GoldChangedEventHandler(int newGold);
[Signal] public delegate void PartyChangedEventHandler();
// ===== 游戏状态 =====
private RpgGameState _gameState = RpgGameState.MainMenu;
public RpgGameState GameState
{
get => _gameState;
set => ChangeGameState(value);
}
// ===== 玩家数据 =====
private int _gold = 100; // 金币
private List<CharacterStats> _party = new(); // 队伍
private List<InventorySlot> _inventory = new(); // 背包
private List<string> _completedQuests = new(); // 已完成任务ID
private List<string> _activeQuests = new(); // 进行中任务ID
private Dictionary<string, bool> _flags = new(); // 游戏标记(剧情进度等)
private int _playTime = 0; // 游戏时长(秒)
private string _currentMap = "town_main"; // 当前所在地图
// ===== 属性 =====
public int Gold => _gold;
public IReadOnlyList<CharacterStats> Party => _party.AsReadOnly();
public IReadOnlyList<InventorySlot> Inventory => _inventory.AsReadOnly();
public string CurrentMap => _currentMap;
public override void _Ready()
{
GD.Print("伏魔记 GameManager 已初始化");
}
public override void _Process(double delta)
{
// 累计游戏时长(非暂停状态)
if (_gameState != RpgGameState.MainMenu
&& _gameState != RpgGameState.GameMenu)
{
_playTime += (int)(delta);
}
}
// ===== 状态管理 =====
private void ChangeGameState(RpgGameState newState)
{
if (_gameState == newState) return;
_gameState = newState;
GetTree().Paused = (newState == RpgGameState.GameMenu
|| newState == RpgGameState.Cutscene);
EmitSignal(SignalName.GameStateChanged, newState);
GD.Print($"游戏状态 → {newState}");
}
// ===== 金币管理 =====
public bool CanAfford(int amount) => _gold >= amount;
public void AddGold(int amount)
{
_gold += amount;
EmitSignal(SignalName.GoldChanged, _gold);
}
public bool SpendGold(int amount)
{
if (_gold < amount) return false;
_gold -= amount;
EmitSignal(SignalName.GoldChanged, _gold);
return true;
}
// ===== 队伍管理 =====
public bool AddPartyMember(CharacterStats member)
{
if (_party.Count >= RpgConstants.MaxPartySize) return false;
_party.Add(member);
EmitSignal(SignalName.PartyChanged);
return true;
}
public void RemovePartyMember(int index)
{
if (index >= 0 && index < _party.Count)
{
_party.RemoveAt(index);
EmitSignal(SignalName.PartyChanged);
}
}
// ===== 游戏标记 =====
public void SetFlag(string flagName, bool value)
{
_flags[flagName] = value;
}
public bool GetFlag(string flagName)
{
return _flags.ContainsKey(flagName) && _flags[flagName];
}
// ===== 存档数据打包 =====
public Godot.Collections.Dictionary GetSaveData()
{
return new Godot.Collections.Dictionary
{
{ "gold", _gold },
{ "current_map", _currentMap },
{ "play_time", _playTime },
{ "flags", new Godot.Collections.Dictionary(_flags) },
{ "active_quests", new Godot.Collections.Array(_activeQuests) },
{ "completed_quests", new Godot.Collections.Array(_completedQuests) }
};
}
}GDScript
extends Node
## 伏魔记全局游戏管理器
## 统筹队伍、背包、任务、场景切换等所有子系统
# ===== 信号 =====
signal game_state_changed(new_state: int)
signal gold_changed(new_gold: int)
signal party_changed
# ===== 游戏状态 =====
var _game_state: int = RpgGameState.MAIN_MENU
var game_state: int:
get:
return _game_state
set(value):
change_game_state(value)
# ===== 玩家数据 =====
var _gold: int = 100 ## 金币
var _party: Array[CharacterStats] = [] ## 队伍
var _inventory: Array = [] ## 背包
var _completed_quests: Array[String] = [] ## 已完成任务ID
var _active_quests: Array[String] = [] ## 进行中任务ID
var _flags: Dictionary = {} ## 游戏标记
var _play_time: int = 0 ## 游戏时长(秒)
var _current_map: String = "town_main" ## 当前所在地图
# ===== 属性 =====
var gold: int:
get: return _gold
var current_map: String:
get: return _current_map
func _ready() -> void:
print("伏魔记 GameManager 已初始化")
func _process(delta: float) -> void:
# 累计游戏时长(非暂停状态)
if _game_state != RpgGameState.MAIN_MENU \
and _game_state != RpgGameState.GAME_MENU:
_play_time += int(delta)
## 状态管理
func change_game_state(new_state: int) -> void:
if _game_state == new_state:
return
_game_state = new_state
get_tree().paused = (new_state == RpgGameState.GAME_MENU \
or new_state == RpgGameState.CUTSCENE)
game_state_changed.emit(new_state)
## 金币管理
func can_afford(amount: int) -> bool:
return _gold >= amount
func add_gold(amount: int) -> void:
_gold += amount
gold_changed.emit(_gold)
func spend_gold(amount: int) -> bool:
if _gold < amount:
return false
_gold -= amount
gold_changed.emit(_gold)
return true
## 队伍管理
func add_party_member(member: CharacterStats) -> bool:
if _party.size() >= RpgConstants.MAX_PARTY_SIZE:
return false
_party.append(member)
party_changed.emit()
return true
func remove_party_member(index: int) -> void:
if index >= 0 and index < _party.size():
_party.remove_at(index)
party_changed.emit()
## 游戏标记
func set_flag(flag_name: String, value: bool) -> void:
_flags[flag_name] = value
func get_flag(flag_name: String) -> bool:
return _flags.get(flag_name, false)
## 存档数据打包
func get_save_data() -> Dictionary:
return {
"gold": _gold,
"current_map": _current_map,
"play_time": _play_time,
"flags": _flags.duplicate(),
"active_quests": _active_quests.duplicate(),
"completed_quests": _completed_quests.duplicate()
}2.6 SceneManager——场景切换管理器
RPG有大量的场景切换——从城镇到地下城、从探索到战斗、从战斗回到城镇。SceneManager 负责管理这些切换,就像一个"交通指挥员",指挥你在不同的游戏场景之间移动。
C
using Godot;
/// <summary>
/// 场景切换管理器
/// 处理不同游戏场景之间的平滑切换
/// </summary>
public partial class SceneManager : Node
{
/// <summary>
/// 场景路径常量
/// </summary>
public static class ScenePaths
{
public const string MainMenu = "res://scenes/ui/main_menu.tscn";
public const string TownMain = "res://scenes/maps/town_main.tscn";
public const string DungeonForest = "res://scenes/maps/dungeon_forest.tscn";
public const string DungeonCave = "res://scenes/maps/dungeon_cave.tscn";
public const string Battle = "res://scenes/battle/battle_scene.tscn";
}
// 场景切换过渡动画
private ColorRect _transitionRect;
private Tween _tween;
private float _transitionDuration = 0.5f;
public override void _Ready()
{
// 创建全屏黑色矩形,用于淡入淡出效果
_transitionRect = new ColorRect
{
Color = new Color(0, 0, 0, 0),
ZIndex = 100,
MouseFilter = MouseFilterEnum.Ignore
};
AddChild(_transitionRect);
}
/// <summary>
/// 切换到指定场景(带过渡动画)
/// </summary>
public void ChangeScene(string scenePath, Vector2? spawnPosition = null)
{
// 淡出到黑色
_tween = CreateTween();
_tween.TweenProperty(_transitionRect, "color:a", 1.0, _transitionDuration);
// 淡出完成后切换场景
_tween.TweenCallback(Callable.From(() =>
{
// 切换场景
GetTree().ChangeSceneToFile(scenePath);
// 如果指定了出生位置,通知场景
if (spawnPosition.HasValue)
{
var player = GetTree().CurrentScene?.FindChild("Player");
if (player != null)
{
((Node2D)player).GlobalPosition = spawnPosition.Value;
}
}
// 从黑色淡入
var fadeIn = CreateTween();
fadeIn.TweenProperty(_transitionRect, "color:a", 0.0, _transitionDuration);
}));
}
/// <summary>
/// 进入战斗场景
/// </summary>
public void EnterBattle(string enemyGroupId)
{
GameManager.Instance.GameState = RpgGameState.Battle;
ChangeScene(ScenePaths.Battle);
}
/// <summary>
/// 退出战斗回到地图
/// </summary>
public void ExitBattle()
{
GameManager.Instance.GameState = RpgGameState.TownExplore;
ChangeScene(GameManager.Instance.CurrentMap);
}
}GDScript
extends Node
## 场景切换管理器
## 处理不同游戏场景之间的平滑切换
## 场景路径常量
const SCENE_MAIN_MENU := "res://scenes/ui/main_menu.tscn"
const SCENE_TOWN_MAIN := "res://scenes/maps/town_main.tscn"
const SCENE_DUNGEON_FOREST := "res://scenes/maps/dungeon_forest.tscn"
const SCENE_DUNGEON_CAVE := "res://scenes/maps/dungeon_cave.tscn"
const SCENE_BATTLE := "res://scenes/battle/battle_scene.tscn"
# 场景切换过渡动画
var _transition_rect: ColorRect
var _tween: Tween
var _transition_duration: float = 0.5
func _ready() -> void:
# 创建全屏黑色矩形,用于淡入淡出效果
_transition_rect = ColorRect.new()
_transition_rect.color = Color(0, 0, 0, 0)
_transition_rect.z_index = 100
_transition_rect.mouse_filter = Control.MOUSE_FILTER_IGNORE
# 设置全屏大小
_transition_rect.set_anchors_preset(Control.PRESET_FULL_RECT)
add_child(_transition_rect)
## 切换到指定场景(带过渡动画)
func change_scene(scene_path: String, spawn_position: Vector2 = Vector2.ZERO) -> void:
# 淡出到黑色
_tween = create_tween()
_tween.tween_property(_transition_rect, "color:a", 1.0, _transition_duration)
# 淡出完成后切换场景
_tween.tween_callback(_do_change_scene.bind(scene_path, spawn_position))
func _do_change_scene(scene_path: String, spawn_position: Vector2) -> void:
# 切换场景
get_tree().change_scene_to_file(scene_path)
# 如果指定了出生位置,通知场景
var player = get_tree().current_scene.find_child("Player")
if player != null:
player.global_position = spawn_position
# 从黑色淡入
var fade_in = create_tween()
fade_in.tween_property(_transition_rect, "color:a", 0.0, _transition_duration)
## 进入战斗场景
func enter_battle(enemy_group_id: String) -> void:
GameManager.game_state = RpgGameState.BATTLE
change_scene(SCENE_BATTLE)
## 退出战斗回到地图
func exit_battle() -> void:
GameManager.game_state = RpgGameState.TOWN_EXPLORE
change_scene(GameManager.current_map)2.7 背包物品数据结构
RPG里物品种类繁多——武器、防具、药材、关键道具等。我们需要定义一个通用的物品数据结构。
C
using Godot;
/// <summary>
/// 物品类型枚举
/// </summary>
public enum ItemType
{
Consumable, // 消耗品(药材、食物)
Weapon, // 武器
Armor, // 防具
Accessory, // 饰品
KeyItem // 关键道具(剧情物品,不可丢弃)
}
/// <summary>
/// 物品数据定义
/// </summary>
public class ItemData
{
public string Id { get; set; } // 物品唯一ID
public string Name { get; set; } // 物品名称
public string Description { get; set; } // 物品描述
public ItemType Type { get; set; } // 物品类型
public int Price { get; set; } // 商店售价
public Texture2D Icon { get; set; } // 物品图标
public bool IsStackable { get; set; } // 是否可堆叠
public int MaxStack { get; set; } // 最大堆叠数
// 消耗品专用属性
public int HealHp { get; set; } // 恢复HP数值
public int HealMp { get; set; } // 恢复MP数值
// 装备专用属性
public int AttackBonus { get; set; } // 攻击力加成
public int DefenseBonus { get; set; } // 防御力加成
public int SpeedBonus { get; set; } // 速度加成
}
/// <summary>
/// 背包格子——记录某个物品及其数量
/// </summary>
public class InventorySlot
{
public ItemData Item { get; set; }
public int Quantity { get; set; }
public InventorySlot(ItemData item, int quantity = 1)
{
Item = item;
Quantity = quantity;
}
}GDScript
## 物品类型枚举
enum ItemType {
CONSUMABLE, ## 消耗品(药材、食物)
WEAPON, ## 武器
ARMOR, ## 防具
ACCESSORY, ## 饰品
KEY_ITEM ## 关键道具(剧情物品,不可丢弃)
}
## 物品数据定义
class_name ItemData
var id: String ## 物品唯一ID
var name: String ## 物品名称
var description: String ## 物品描述
var type: ItemType ## 物品类型
var price: int ## 商店售价
var icon: Texture2D ## 物品图标
var is_stackable: bool ## 是否可堆叠
var max_stack: int ## 最大堆叠数
# 消耗品专用属性
var heal_hp: int ## 恢复HP数值
var heal_mp: int ## 恢复MP数值
# 装备专用属性
var attack_bonus: int ## 攻击力加成
var defense_bonus: int ## 防御力加成
var speed_bonus: int ## 速度加成
## 背包格子——记录某个物品及其数量
class_name InventorySlot
var item: ItemData
var quantity: int
func _init(item_data: ItemData, qty: int = 1) -> void:
item = item_data
quantity = qty2.8 场景骨架搭建
主场景层级
Main (Node) → 附加脚本: game_manager.gd/.cs
├── SceneManager (Node) → 场景切换管理器
├── MapContainer (Node2D) → 地图容器(动态加载地图)
├── UILayer (CanvasLayer) → UI层
│ ├── HUD (Control) ← 游戏内HUD(HP/MP条、金币)
│ ├── DialogueBox (Control) ← 对话框
│ ├── BattleUI (Control) ← 战斗UI
│ ├── MainMenu (Control) ← 主菜单
│ ├── GameMenu (Control) ← 游戏内菜单
│ ├── InventoryUI (Control) ← 背包界面
│ └── ShopUI (Control) ← 商店界面
└── TransitionOverlay (ColorRect) ← 场景切换遮罩2.9 本章小结
| 内容 | 说明 |
|---|---|
| 创建项目 | Godot中新建2D项目,配置960x640窗口,添加RPG按键映射 |
| 目录结构 | scenes/scripts/data/assets四大目录,按功能细分 |
| 常量定义 | 集中管理瓦片大小、角色属性初始值、背包上限等 |
| GameManager | 全局管理器:队伍、金币、背包、任务、存档 |
| SceneManager | 场景切换:淡入淡出过渡,支持指定出生位置 |
| 物品数据 | 物品类型、属性、背包格子的数据结构定义 |
下一章我们将搭建瓦片地图世界,实现角色的城镇探索和地图切换功能。
