120 lines
3.7 KiB
C++
120 lines
3.7 KiB
C++
#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 ¤t, const Vec2 &target, Vec2 ¤tVelocity, 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;
|
||
} |