Files
DNF_DEV/source_game/Global/GameCamera.cpp

120 lines
3.7 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "GameCamera.h"
#include "EngineCore/Game.h"
#include "Actor/Map/GameMap.h"
#include "Actor/Object/BaseObject.h"
#include "Global/Global_Game.h"
#include <algorithm>
void GameCamera::SetFromActor(BaseObject *actor)
{
// 如果原来有跟随对象
if (this->_FromActor)
{
this->_FromActor->RemoveCallbackOnUpdate("Camear Update");
}
this->_FromActor = actor;
actor->SetCallbackOnUpdate("Camear Update", [](float deltaTime) mutable
{ Global_Game::GetInstance().GetCamera()->Update(deltaTime); });
}
void GameCamera::Update(float deltaTime)
{
SyncPosByFromParent(deltaTime);
}
void GameCamera::SyncPos(float deltaTime)
{
}
void GameCamera::SetPos(float x, float y, float z)
{
// this->X = x;
// this->Y = y;
// this->Z = z;
}
void GameCamera::AddPos(float x, float y, float z)
{
// this->X += x;
// this->Y += y;
// this->Z += z;
}
void GameCamera::SyncPosByFromParent(float deltaTime)
{
if (this->_FromActor == nullptr)
{
return;
}
float targetX = _FromActor->Position.x;
float targetY = _FromActor->Position.y;
if (_isSmoothMoving)
{
// 平滑移动计算
Vec2 targetPosition(targetX, targetY);
_currentPosition = SmoothDamp(_currentPosition, targetPosition, _velocity, _smoothTime, _maxSpeed, deltaTime);
}
else
{
_currentPosition.x = targetX;
_currentPosition.y = targetY;
}
}
Vec2 GameCamera::SmoothDamp(const Vec2 &current, const Vec2 &target, Vec2 &currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
{
// 平滑时间为0时直接返回目标位置并重置速度
if (smoothTime <= 0.f)
{
currentVelocity = Vec2(0, 0);
return target;
}
// 临界阻尼系数计算(避免过冲的核心参数)
const float omega = 2.0f / smoothTime;
const float x = omega * deltaTime;
const float expTerm = 1.0f / (1.0f + x + 0.48f * x * x + 0.235f * x * x * x);
// 计算当前位置与目标的差值
Vec2 delta = target - current;
// 计算目标速度(基于阻尼公式和当前差值)
// 注意:这里先通过浮点计算保持精度,最后转换为整数
const float tx = delta.x * (omega * omega * deltaTime) - currentVelocity.x * (1.0f + 0.48f * x) * x;
const float ty = delta.y * (omega * omega * deltaTime) - currentVelocity.y * (1.0f + 0.48f * x) * x;
Vec2 targetVelocity(tx, ty);
// 应用速度衰减(指数平滑)
currentVelocity += targetVelocity;
currentVelocity = Vec2(currentVelocity.x * expTerm, currentVelocity.y * expTerm);
// 限制最大速度如果设置了maxSpeed
if (maxSpeed > 0)
{
// 计算当前速度的模长(浮点精度)
const float speedSq = currentVelocity.x * currentVelocity.x + currentVelocity.y * currentVelocity.y;
const float maxSpeedSq = maxSpeed * maxSpeed;
if (speedSq > maxSpeedSq)
{
// 速度超限,按比例缩放至最大速度
const float scale = maxSpeed / sqrtf(speedSq);
currentVelocity = Vec2(currentVelocity.x * scale, currentVelocity.y * scale);
}
}
// 计算新位置(当前位置 + 速度 * 时间)
Vec2 newPos = current + Vec2(currentVelocity.x * deltaTime, currentVelocity.y * deltaTime);
// 检测过冲:如果新位置已越过目标,直接锁定目标并重置速度
// 点积 > 0 表示方向相反(已超过目标)
const float dot = delta.x * (newPos.x - target.x) + delta.y * (newPos.y - target.y);
if (dot > 0)
{
newPos = target;
currentVelocity = Vec2(0, 0);
}
return newPos;
}