refactor(character): 使用整数坐标优化角色位置同步
- 将CharacterWorldPosition改为使用整数坐标,避免浮点精度问题 - 添加位置余数处理,确保移动平滑性 - 统一角色位置同步逻辑到SyncActorPositionFromWorld方法 - 修改地图移动检测使用整数坐标判断
This commit is contained in:
@@ -54,13 +54,17 @@ enum class CharacterStateId {
|
||||
|
||||
/// 角色的逻辑世界坐标。x/y 是地面平面,z 是高度轴。
|
||||
struct CharacterWorldPosition {
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float z = 0.0f;
|
||||
int32 x = 0;
|
||||
int32 y = 0;
|
||||
int32 z = 0;
|
||||
|
||||
/// 当前项目的 2.5D 投影:地面 y 决定站位,高度 z 决定视觉抬升。
|
||||
Vec2 ToScreenPosition() const { return Vec2(x, y - z); }
|
||||
Vec2 ToGroundPosition() const { return Vec2(x, y); }
|
||||
Vec2 ToScreenPosition() const {
|
||||
return Vec2(static_cast<float>(x), static_cast<float>(y - z));
|
||||
}
|
||||
Vec2 ToGroundPosition() const {
|
||||
return Vec2(static_cast<float>(x), static_cast<float>(y));
|
||||
}
|
||||
};
|
||||
|
||||
/// 运动器只负责推进坐标和速度,不直接决定状态流转。
|
||||
@@ -77,8 +81,14 @@ struct CharacterMotor {
|
||||
float gravity = 1600.0f;
|
||||
|
||||
void SetGroundPosition(const Vec2& groundPosition) {
|
||||
position.x = groundPosition.x;
|
||||
position.y = groundPosition.y;
|
||||
position.x = RoundWorldCoordinate(groundPosition.x);
|
||||
position.y = RoundWorldCoordinate(groundPosition.y);
|
||||
positionRemainder_ = Vec2::Zero();
|
||||
}
|
||||
|
||||
void SetWorldPosition(const CharacterWorldPosition& worldPosition) {
|
||||
position = worldPosition;
|
||||
ClearPositionRemainders();
|
||||
}
|
||||
|
||||
void ApplyGroundInput(float moveX, float moveY, float speedScale = 1.0f) {
|
||||
@@ -113,42 +123,75 @@ struct CharacterMotor {
|
||||
void Jump() {
|
||||
grounded = false;
|
||||
verticalVelocity = jumpSpeed;
|
||||
if (position.z < 0.0f) {
|
||||
position.z = 0.0f;
|
||||
if (position.z < 0) {
|
||||
position.z = 0;
|
||||
verticalPositionRemainder_ = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void Update(float deltaTime) {
|
||||
position.x += groundVelocity.x * deltaTime;
|
||||
position.y += groundVelocity.y * deltaTime;
|
||||
positionRemainder_.x += groundVelocity.x * deltaTime;
|
||||
positionRemainder_.y += groundVelocity.y * deltaTime;
|
||||
if (forcedSlideRemainingTime > 0.0f && forcedSlideVelocity.lengthSquared() > 0.0f) {
|
||||
float slideDeltaTime = deltaTime < forcedSlideRemainingTime
|
||||
? deltaTime
|
||||
: forcedSlideRemainingTime;
|
||||
position.x += forcedSlideVelocity.x * slideDeltaTime;
|
||||
position.y += forcedSlideVelocity.y * slideDeltaTime;
|
||||
positionRemainder_.x += forcedSlideVelocity.x * slideDeltaTime;
|
||||
positionRemainder_.y += forcedSlideVelocity.y * slideDeltaTime;
|
||||
forcedSlideRemainingTime -= slideDeltaTime;
|
||||
if (forcedSlideRemainingTime <= 0.0f) {
|
||||
ClearForcedSlide();
|
||||
}
|
||||
}
|
||||
position.x += ConsumeWholeUnits(positionRemainder_.x);
|
||||
position.y += ConsumeWholeUnits(positionRemainder_.y);
|
||||
|
||||
if (!grounded || position.z > 0.0f || verticalVelocity > 0.0f) {
|
||||
position.z += verticalVelocity * deltaTime;
|
||||
if (!grounded || position.z > 0 || verticalVelocity > 0.0f) {
|
||||
verticalPositionRemainder_ += verticalVelocity * deltaTime;
|
||||
verticalVelocity -= gravity * deltaTime;
|
||||
grounded = false;
|
||||
position.z += ConsumeWholeUnits(verticalPositionRemainder_);
|
||||
|
||||
if (position.z <= 0.0f) {
|
||||
position.z = 0.0f;
|
||||
if (position.z <= 0) {
|
||||
position.z = 0;
|
||||
verticalVelocity = 0.0f;
|
||||
verticalPositionRemainder_ = 0.0f;
|
||||
grounded = true;
|
||||
}
|
||||
} else {
|
||||
position.z = 0.0f;
|
||||
position.z = 0;
|
||||
verticalVelocity = 0.0f;
|
||||
verticalPositionRemainder_ = 0.0f;
|
||||
grounded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static int32 RoundWorldCoordinate(float value) {
|
||||
return static_cast<int32>(std::lround(value));
|
||||
}
|
||||
|
||||
static int32 ConsumeWholeUnits(float& remainder) {
|
||||
if (remainder >= 1.0f) {
|
||||
int32 wholeUnits = static_cast<int32>(std::floor(remainder));
|
||||
remainder -= static_cast<float>(wholeUnits);
|
||||
return wholeUnits;
|
||||
}
|
||||
if (remainder <= -1.0f) {
|
||||
int32 wholeUnits = static_cast<int32>(std::ceil(remainder));
|
||||
remainder -= static_cast<float>(wholeUnits);
|
||||
return wholeUnits;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ClearPositionRemainders() {
|
||||
positionRemainder_ = Vec2::Zero();
|
||||
verticalPositionRemainder_ = 0.0f;
|
||||
}
|
||||
|
||||
Vec2 positionRemainder_ = Vec2::Zero();
|
||||
float verticalPositionRemainder_ = 0.0f;
|
||||
};
|
||||
|
||||
/// 逻辑动作定义。这里只保留显式注册的逻辑入口名。
|
||||
|
||||
@@ -170,6 +170,7 @@ private:
|
||||
void CommitPendingActionContext(const std::string& defaultRequestedActionId,
|
||||
const std::string& defaultSourceActionId,
|
||||
CharacterStateId defaultSourceStateId);
|
||||
void SyncActorPositionFromWorld();
|
||||
bool SetActionStrict(const std::string& actionName,
|
||||
const char* phase,
|
||||
const std::string& requestedActionId);
|
||||
|
||||
Reference in New Issue
Block a user