Files
Frostbite2D/Game/src/world/GameTown.cpp
Lenheart 62b0f6dafd feat(渲染): 添加虚拟分辨率支持并重构相机系统
实现虚拟分辨率渲染系统,支持不同缩放模式
重构相机控制器以使用虚拟分辨率计算可见区域
移除硬编码的屏幕尺寸,改为动态获取
添加分辨率状态管理及相关工具函数
更新窗口和渲染器以处理分辨率变化
2026-04-06 23:17:26 +08:00

150 lines
3.9 KiB
C++

#include "world/GameTown.h"
#include "character/CharacterObject.h"
#include <SDL2/SDL.h>
#include <algorithm>
#include <cmath>
namespace frostbite2D {
namespace {
Vec2 RoundWorldPoint(const Vec2& pos) {
return Vec2(static_cast<float>(std::lround(pos.x)),
static_cast<float>(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<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;
}
RefPtr<GameMap> GameTown::GetCurrentArea() const {
if (curMapIndex_ == -1) {
return nullptr;
}
return GetArea(curMapIndex_);
}
void GameTown::AddCharacter(RefPtr<Actor> 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<CharacterObject*>(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