feat: 添加游戏核心模块,包括地图、角色、场景和世界管理

实现游戏基础架构,包含以下主要功能:
- 地图系统:支持地图加载、图层管理和相机控制
- 角色系统:实现角色装备、动画和行为管理
- 场景系统:提供测试场景和世界场景切换
- 世界管理:处理城镇和区域切换逻辑
- 数据加载:添加角色和装备配置加载器

这些改动为游戏开发奠定了基础框架,支持后续功能扩展
This commit is contained in:
2026-04-02 23:32:44 +08:00
parent ec16aeffa6
commit b5c432e77a
23 changed files with 934 additions and 26 deletions

117
Game/src/world/GameTown.cpp Normal file
View File

@@ -0,0 +1,117 @@
#include "world/GameTown.h"
#include <SDL2/SDL.h>
#include <algorithm>
namespace frostbite2D {
GameTown::GameTown() = default;
bool GameTown::Init(int index, const std::string& townPath) {
game::TownConfig config;
if (!game::loadTownConfig(townPath, config)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "GameTown: failed to init town %d (%s)",
index, townPath.c_str());
return false;
}
name_ = config.townName;
enteringTitle_ = config.enteringTitle;
enteringCutscene_ = config.enteringCutscene;
needQuestId_ = config.needQuestId;
needLevel_ = config.needLevel;
mapList_.clear();
curMapIndex_ = -1;
sariaRoomId_ = -1;
sariaRoomPos_ = Vec2(-1.0f, -1.0f);
for (const auto& [areaId, areaConfig] : config.areas) {
auto map = MakePtr<GameMap>();
if (!map->LoadMap(areaConfig.mapPath)) {
continue;
}
MapInfo info;
info.areaId = areaId;
info.map = map;
info.type = areaConfig.mapType;
info.generatePos = areaConfig.generatePos;
mapList_.push_back(info);
if (info.type == "gate") {
sariaRoomId_ = areaId;
sariaRoomPos_ = areaConfig.generatePos;
}
}
std::sort(mapList_.begin(), mapList_.end(),
[](const MapInfo& a, const MapInfo& b) { return a.areaId < b.areaId; });
return !mapList_.empty();
}
RefPtr<GameMap> GameTown::GetArea(int index) const {
auto it = std::find_if(mapList_.begin(), mapList_.end(),
[index](const MapInfo& info) { return info.areaId == index; });
if (it == mapList_.end()) {
return nullptr;
}
return it->map;
}
void GameTown::AddCharacter(RefPtr<Actor> actor, int areaIndex) {
int targetMapIndex = areaIndex;
if (areaIndex == -2) {
targetMapIndex = sariaRoomId_ != -1 ? sariaRoomId_ : (mapList_.empty() ? -1 : mapList_.front().areaId);
}
auto mapIt = std::find_if(mapList_.begin(), mapList_.end(),
[targetMapIndex](const MapInfo& info) {
return info.areaId == targetMapIndex;
});
if (mapIt == mapList_.end()) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"GameTown: target area %d not found, fallback to first map", targetMapIndex);
if (mapList_.empty()) {
return;
}
mapIt = mapList_.begin();
}
if (curMapIndex_ != -1) {
auto oldMap = GetArea(curMapIndex_);
if (oldMap) {
RemoveChild(oldMap);
}
}
if (actor && actor->GetParent()) {
actor->GetParent()->RemoveChild(actor);
}
AddChild(mapIt->map);
cameraController_.SetMap(mapIt->map.Get());
cameraController_.SetZoom(1.2f);
cameraController_.SetTarget(actor.Get());
cameraController_.SnapToDefaultFocus();
if (actor) {
cameraController_.SetDebugEnabled(false);
if (areaIndex == -2 && sariaRoomPos_.x >= 0.0f && sariaRoomPos_.y >= 0.0f) {
actor->SetPosition(sariaRoomPos_);
}
mapIt->map->AddObject(actor);
cameraController_.SetFocus(actor->GetPosition());
} else {
cameraController_.SetDebugEnabled(true);
}
mapIt->map->Enter();
curMapIndex_ = mapIt->areaId;
}
void GameTown::Update(float deltaTime) {
Actor::Update(deltaTime);
cameraController_.Update(deltaTime);
}
} // namespace frostbite2D

View File

@@ -0,0 +1,84 @@
#include "world/GameWorld.h"
#include "map/GameDataLoader.h"
#include <SDL2/SDL.h>
#include <frostbite2D/scene/scene_manager.h>
namespace frostbite2D {
GameWorld::GameWorld() = default;
void GameWorld::onEnter() {
Scene::onEnter();
if (initialized_) {
return;
}
initialized_ = InitWorld();
}
void GameWorld::onExit() {
Scene::onExit();
}
bool GameWorld::InitWorld() {
townPathMap_ = game::loadTownList();
if (townPathMap_.empty()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "GameWorld: no town entries found");
return false;
}
for (const auto& [townId, townPath] : townPathMap_) {
auto town = MakePtr<GameTown>();
if (!town->Init(townId, townPath)) {
continue;
}
townMap_[townId] = town;
}
if (townMap_.empty()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "GameWorld: failed to create any town");
return false;
}
AddCharacter(nullptr, townMap_.begin()->first);
return true;
}
void GameWorld::AddCharacter(RefPtr<Actor> actor, int townId) {
auto it = townMap_.find(townId);
if (it == townMap_.end()) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "GameWorld: town %d not found", townId);
return;
}
mainActor_ = actor;
curTown_ = townId;
it->second->AddCharacter(actor);
AddChild(it->second);
}
void GameWorld::MoveCharacter(RefPtr<Actor> actor, int townId, int area) {
auto townIt = townMap_.find(townId);
if (townIt == townMap_.end()) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "GameWorld: target town %d missing", townId);
return;
}
if (curTown_ != -1) {
auto currentTown = townMap_.find(curTown_);
if (currentTown != townMap_.end()) {
RemoveChild(currentTown->second);
}
}
curTown_ = townId;
mainActor_ = actor;
townIt->second->AddCharacter(actor, area);
AddChild(townIt->second);
}
GameWorld* GameWorld::GetWorld() {
return dynamic_cast<GameWorld*>(SceneManager::get().GetCurrentScene());
}
} // namespace frostbite2D