#include "world/GameTown.h" #include "character/CharacterObject.h" #include #include #include namespace frostbite2D { namespace { Vec2 RoundWorldPoint(const Vec2& pos) { return Vec2(static_cast(std::lround(pos.x)), static_cast(std::lround(pos.y))); } } // namespace GameTown::GameTown() { EnableEventReceive(); } 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(); 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 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; } RefPtr GameTown::GetCurrentArea() const { if (curMapIndex_ == -1) { return nullptr; } return GetArea(curMapIndex_); } void GameTown::AddCharacter(RefPtr actor, int areaIndex) { int targetMapIndex = areaIndex; if (areaIndex == -2) { if (sariaRoomId_ != -1) { targetMapIndex = sariaRoomId_; } else { targetMapIndex = mapList_.empty() ? -1 : mapList_.front().areaId; SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "GameTown: no gate area configured, fallback to first area %d", targetMapIndex); } } 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_.SetTarget(actor.Get()); cameraController_.SnapToDefaultFocus(); if (actor) { cameraController_.SetDebugEnabled(false); if (areaIndex == -2 && sariaRoomPos_.x >= 0.0f && sariaRoomPos_.y >= 0.0f) { Vec2 spawnPos = RoundWorldPoint(sariaRoomPos_); if (auto* character = dynamic_cast(actor.Get())) { character->SetCharacterPosition(spawnPos); } else { actor->SetPosition(spawnPos); } } 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