Files
Frostbite2D/Game/src/Camera/GameCameraController.cpp
Lenheart ec16aeffa6 feat: 实现游戏摄像机控制器并优化地图系统
重构地图系统,增加摄像机控制器管理相机行为。主要变更包括:
- 新增 GameCameraController 类,支持跟随目标和调试模式
- 重构 GameMap 类,分离相机逻辑到控制器
- 优化地图资源加载和同步逻辑
- 改进动画系统的事件处理
- 添加地图测试场景用于快速验证
2026-04-02 20:07:42 +08:00

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