重构地图系统,增加摄像机控制器管理相机行为。主要变更包括: - 新增 GameCameraController 类,支持跟随目标和调试模式 - 重构 GameMap 类,分离相机逻辑到控制器 - 优化地图资源加载和同步逻辑 - 改进动画系统的事件处理 - 添加地图测试场景用于快速验证
194 lines
4.5 KiB
C++
194 lines
4.5 KiB
C++
#include "Camera/GameCameraController.h"
|
|
#include "Actor/GameMap.h"
|
|
#include <SDL2/SDL.h>
|
|
#include <cmath>
|
|
#include <frostbite2D/graphics/camera.h>
|
|
#include <frostbite2D/graphics/renderer.h>
|
|
#include <algorithm>
|
|
|
|
namespace frostbite2D {
|
|
|
|
namespace {
|
|
|
|
constexpr float kScreenWidth = 1280.0f;
|
|
constexpr float kScreenHeight = 720.0f;
|
|
constexpr int kDebugStickDeadzone = 8000;
|
|
|
|
float normalizeControllerAxis(int16 value) {
|
|
float magnitude = static_cast<float>(value);
|
|
if (std::abs(magnitude) <= static_cast<float>(kDebugStickDeadzone)) {
|
|
return 0.0f;
|
|
}
|
|
|
|
float sign = magnitude < 0.0f ? -1.0f : 1.0f;
|
|
float normalized =
|
|
(std::abs(magnitude) - static_cast<float>(kDebugStickDeadzone)) /
|
|
(32767.0f - static_cast<float>(kDebugStickDeadzone));
|
|
return std::clamp(normalized, 0.0f, 1.0f) * sign;
|
|
}
|
|
|
|
}
|
|
|
|
GameCameraController::~GameCameraController() {
|
|
closeDebugController();
|
|
}
|
|
|
|
void GameCameraController::SetMap(GameMap* map) {
|
|
map_ = map;
|
|
initialized_ = false;
|
|
}
|
|
|
|
void GameCameraController::SetTarget(Actor* target) {
|
|
target_ = target;
|
|
}
|
|
|
|
void GameCameraController::ClearTarget() {
|
|
target_ = nullptr;
|
|
}
|
|
|
|
void GameCameraController::SetDebugEnabled(bool enabled) {
|
|
debugEnabled_ = enabled;
|
|
if (debugEnabled_) {
|
|
openDebugController();
|
|
} else {
|
|
closeDebugController();
|
|
}
|
|
}
|
|
|
|
void GameCameraController::SetZoom(float zoom) {
|
|
zoom_ = std::max(zoom, 0.01f);
|
|
if (map_) {
|
|
focus_ = map_->ClampCameraFocus(focus_, zoom_);
|
|
}
|
|
applyFocus();
|
|
}
|
|
|
|
void GameCameraController::SetFocus(const Vec2& focus) {
|
|
focus_ = map_ ? map_->ClampCameraFocus(focus, zoom_) : focus;
|
|
initialized_ = true;
|
|
applyFocus();
|
|
}
|
|
|
|
void GameCameraController::SnapToDefaultFocus() {
|
|
if (!map_) {
|
|
return;
|
|
}
|
|
|
|
focus_ = map_->ClampCameraFocus(map_->GetDefaultCameraFocus(), zoom_);
|
|
initialized_ = true;
|
|
applyFocus();
|
|
}
|
|
|
|
void GameCameraController::Update(float deltaTime) {
|
|
if (!map_) {
|
|
return;
|
|
}
|
|
|
|
if (!initialized_) {
|
|
SnapToDefaultFocus();
|
|
}
|
|
|
|
if (target_) {
|
|
Vec2 targetFocus = target_->GetPosition();
|
|
float t = std::clamp(deltaTime * followLerpSpeed_, 0.0f, 1.0f);
|
|
focus_ = focus_ + (targetFocus - focus_) * t;
|
|
} else if (debugEnabled_) {
|
|
updateDebugInput(deltaTime);
|
|
}
|
|
|
|
focus_ = map_->ClampCameraFocus(focus_, zoom_);
|
|
applyFocus();
|
|
}
|
|
|
|
void GameCameraController::openDebugController() {
|
|
if (debugController_ && SDL_GameControllerGetAttached(debugController_)) {
|
|
return;
|
|
}
|
|
|
|
closeDebugController();
|
|
|
|
int joystickCount = SDL_NumJoysticks();
|
|
for (int i = 0; i < joystickCount; ++i) {
|
|
if (!SDL_IsGameController(i)) {
|
|
continue;
|
|
}
|
|
|
|
debugController_ = SDL_GameControllerOpen(i);
|
|
if (debugController_) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameCameraController::closeDebugController() {
|
|
if (!debugController_) {
|
|
return;
|
|
}
|
|
|
|
SDL_GameControllerClose(debugController_);
|
|
debugController_ = nullptr;
|
|
}
|
|
|
|
void GameCameraController::updateDebugInput(float deltaTime) {
|
|
const uint8* keyboardState = SDL_GetKeyboardState(nullptr);
|
|
float moveX = 0.0f;
|
|
float moveY = 0.0f;
|
|
|
|
if (keyboardState) {
|
|
if (keyboardState[SDL_SCANCODE_A]) {
|
|
moveX -= 1.0f;
|
|
}
|
|
if (keyboardState[SDL_SCANCODE_D]) {
|
|
moveX += 1.0f;
|
|
}
|
|
if (keyboardState[SDL_SCANCODE_W]) {
|
|
moveY -= 1.0f;
|
|
}
|
|
if (keyboardState[SDL_SCANCODE_S]) {
|
|
moveY += 1.0f;
|
|
}
|
|
}
|
|
|
|
if (debugEnabled_ && !debugController_) {
|
|
openDebugController();
|
|
}
|
|
|
|
if (debugController_ && !SDL_GameControllerGetAttached(debugController_)) {
|
|
closeDebugController();
|
|
openDebugController();
|
|
}
|
|
|
|
if (debugController_ && SDL_GameControllerGetAttached(debugController_)) {
|
|
moveX += normalizeControllerAxis(
|
|
SDL_GameControllerGetAxis(debugController_, SDL_CONTROLLER_AXIS_LEFTX));
|
|
moveY += normalizeControllerAxis(
|
|
SDL_GameControllerGetAxis(debugController_, SDL_CONTROLLER_AXIS_LEFTY));
|
|
}
|
|
|
|
moveX = std::clamp(moveX, -1.0f, 1.0f);
|
|
moveY = std::clamp(moveY, -1.0f, 1.0f);
|
|
|
|
if (moveX == 0.0f && moveY == 0.0f) {
|
|
return;
|
|
}
|
|
|
|
focus_.x += moveX * debugMoveSpeed_ * deltaTime;
|
|
focus_.y += moveY * debugMoveSpeed_ * deltaTime;
|
|
}
|
|
|
|
void GameCameraController::applyFocus() const {
|
|
Camera* camera = Renderer::get().getCamera();
|
|
if (!camera || !map_) {
|
|
return;
|
|
}
|
|
|
|
float halfWidth = kScreenWidth * 0.5f / zoom_;
|
|
float halfHeight = kScreenHeight * 0.5f / zoom_;
|
|
Vec2 cameraPos(focus_.x - halfWidth, focus_.y - halfHeight);
|
|
camera->setZoom(zoom_);
|
|
camera->setPosition(cameraPos);
|
|
map_->ApplyCameraFocus(focus_);
|
|
}
|
|
|
|
} // namespace frostbite2D
|