80 lines
2.6 KiB
C++
80 lines
2.6 KiB
C++
#include "camera_controller.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
namespace ns_game {
|
|
|
|
namespace {
|
|
|
|
float clampValue(float value, float minValue, float maxValue) {
|
|
if (maxValue < minValue) {
|
|
return minValue;
|
|
}
|
|
return std::clamp(value, minValue, maxValue);
|
|
}
|
|
|
|
float smoothFactor(float smoothing, float deltaTime) {
|
|
if (smoothing <= 0.0f) {
|
|
return 1.0f;
|
|
}
|
|
return 1.0f - std::exp(-smoothing * std::max(deltaTime, 0.0f));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void CameraController::Configure(const CameraControllerConfig& config) {
|
|
config_ = config;
|
|
}
|
|
|
|
void CameraController::SetWorldBounds(const frostbite2D::Rect& worldBounds) {
|
|
const float width = std::max(worldBounds.width(), config_.viewportWidth);
|
|
const float height = std::max(worldBounds.height(), config_.viewportHeight);
|
|
config_.worldBounds =
|
|
frostbite2D::Rect(worldBounds.left(), worldBounds.top(), width, height);
|
|
}
|
|
|
|
void CameraController::SnapToTarget(frostbite2D::Camera& camera,
|
|
const frostbite2D::Rect& targetBounds) {
|
|
camera.setPosition(clampToWorld(
|
|
resolveDesiredPosition(camera.getPosition(), targetBounds)));
|
|
}
|
|
|
|
void CameraController::Update(frostbite2D::Camera& camera,
|
|
const frostbite2D::Rect& targetBounds,
|
|
float deltaTime) {
|
|
const frostbite2D::Vec2 current = camera.getPosition();
|
|
const frostbite2D::Vec2 desired =
|
|
clampToWorld(resolveDesiredPosition(current, targetBounds));
|
|
const float t = smoothFactor(config_.smoothing, deltaTime);
|
|
camera.setPosition(frostbite2D::Vec2(
|
|
current.x + (desired.x - current.x) * t,
|
|
current.y + (desired.y - current.y) * t));
|
|
}
|
|
|
|
frostbite2D::Vec2 CameraController::resolveDesiredPosition(
|
|
const frostbite2D::Vec2& currentPosition,
|
|
const frostbite2D::Rect& targetBounds) const {
|
|
frostbite2D::Vec2 desired = currentPosition;
|
|
const float targetCenterX = targetBounds.left() + targetBounds.width() * 0.5f;
|
|
const float screenX = targetCenterX - currentPosition.x;
|
|
if (screenX < config_.deadZone.left()) {
|
|
desired.x = targetCenterX - config_.deadZone.left();
|
|
} else if (screenX > config_.deadZone.right()) {
|
|
desired.x = targetCenterX - config_.deadZone.right();
|
|
}
|
|
desired.y = config_.worldBounds.top();
|
|
return desired;
|
|
}
|
|
|
|
frostbite2D::Vec2 CameraController::clampToWorld(
|
|
const frostbite2D::Vec2& position) const {
|
|
return frostbite2D::Vec2(
|
|
clampValue(position.x, config_.worldBounds.left(),
|
|
config_.worldBounds.right() - config_.viewportWidth),
|
|
clampValue(position.y, config_.worldBounds.top(),
|
|
config_.worldBounds.bottom() - config_.viewportHeight));
|
|
}
|
|
|
|
} // namespace ns_game
|