Smooth player movement and viewbobbing

This commit is contained in:
tovjemam 2025-08-13 16:56:02 +02:00
parent 88c04c1823
commit c941ed9525
2 changed files with 88 additions and 14 deletions

View File

@ -8,7 +8,8 @@ game::Player::Player(World* world, size_t sector_idx, const glm::vec3& position)
pitch_(0.0f),
input_(0),
cam_forward_(0.0f),
cam_up_(0.0f)
cam_up_(0.0f),
cam_right_(0.0f)
{
}
@ -35,34 +36,59 @@ void game::Player::Update(float dt)
float pitch_sin = glm::sin(pitch_);
// MOVEMENT
glm::vec2 velocity_xy(0.0f);
glm::vec2 desire_xy(0.0f);
if (input_ & PI_FORWARD)
velocity_xy.y += 1.0f;
desire_xy.y += 1.0f;
if (input_ & PI_BACKWARD)
velocity_xy.y -= 1.0f;
desire_xy.y -= 1.0f;
if (input_ & PI_LEFT)
velocity_xy.x -= 1.0f;
desire_xy.x -= 1.0f;
if (input_ & PI_RIGHT)
velocity_xy.x += 1.0f;
desire_xy.x += 1.0f;
glm::mat2 movement_basis(
yaw_cos, -yaw_sin,
yaw_sin, yaw_cos
);
float speed = 3.0f; // Base speed
glm::vec2 normalized_velocity_xy(0.0f);
if (glm::length(velocity_xy) > 0.01f)
if (glm::length(desire_xy) > 0.01f)
{
normalized_velocity_xy = glm::normalize(movement_basis * velocity_xy);
desire_xy = glm::normalize(movement_basis * desire_xy);
}
else
{
desire_xy = glm::vec2(0.0f);
}
glm::vec2 target_xy = desire_xy * max_speed_;
glm::vec2 velocity_xy = glm::vec2(velocity_.x, velocity_.y);
glm::vec2 difference_xy = target_xy - velocity_xy;
float dist = glm::length(difference_xy);
if (dist > 0.001f)
{
float accel = acceleration_;
if (glm::length(velocity_xy) > glm::length(target_xy))
{
// If we are moving faster than the target, apply deceleration
accel = deceleration_;
}
float delta = dt * accel;
float t = glm::clamp(delta / dist, 0.0f, 1.0f);
velocity_xy = glm::mix(velocity_xy, target_xy, t);
}
current_speed_ = glm::length(velocity_xy);
glm::vec3 velocity = glm::vec3(
normalized_velocity_xy * speed,
velocity_xy,
-1.0f // No vertical movement for now
);
@ -75,14 +101,52 @@ void game::Player::Update(float dt)
const glm::mat3& occu_basis = occu_->GetBasis();
cam_forward_ = occu_basis * glm::vec3(yaw_sin * pitch_cos, yaw_cos * pitch_cos, pitch_sin);
cam_up_ = occu_basis[2]; // Up vector is always the Z axis in sector space
cam_right_ = glm::cross(cam_forward_, cam_up_);
}
time_ += dt;
}
void game::Player::GetPOV(size_t& sector_idx, glm::vec3& position, glm::vec3& forward, glm::vec3& up) const
{
float scale = 1.0f;
sector_idx = occu_->GetSector().GetIndex();
position = occu_->GetPosition() + cam_up_ * 0.7f;
glm::vec2 bobbing_offset = GetBobbingOffset(time_, 0.01f * current_speed_);
glm::vec3 offset = ((cam_up_ * (0.7f + bobbing_offset.y)) + cam_right_ * bobbing_offset.x) * scale;
position = occu_->GetPosition() + offset;
forward = cam_forward_;
up = cam_up_;
if (touching_portal_ && touching_portal_->link)
{
float sd = glm::dot(glm::vec3(touching_portal_->plane), position) + touching_portal_->plane.w;
// Position is behind portal, render from other sector
if (sd < 0.0f)
{
sector_idx = touching_portal_->link->sector->GetIndex();
position = touching_portal_->tr_position * glm::vec4(position, 1.0f);
forward = touching_portal_->tr_basis * forward;
up = touching_portal_->tr_basis * up;
}
}
}
glm::vec2 game::Player::GetBobbingOffset(float t, float amplitude)
{
// Frequency and amplitude can be adjusted to tweak the effect
float frequency = 10.0f;// 2f * MathHelper.TwoPi; // One full cycle per t=1
float xAmplitude = amplitude;
float yAmplitude = 0.25f * amplitude;
glm::vec2 offset;
offset.x = glm::sin(t * frequency) * xAmplitude;
offset.y = glm::sin(t * frequency * 2.0f) * yAmplitude;
return offset;
}

View File

@ -14,8 +14,16 @@ namespace game
// in occu's sector space
glm::vec3 cam_forward_;
glm::vec3 cam_right_;
glm::vec3 cam_up_;
float max_speed_ = 4.0f;
float acceleration_ = 50.0f;
float deceleration_ = 20.0f;
float time_ = 0.0f;
float current_speed_ = 0.0f;
public:
Player(World* world, size_t sector_idx, const glm::vec3& position);
@ -28,6 +36,8 @@ namespace game
void GetPOV(size_t& sector_idx, glm::vec3& position, glm::vec3& forward, glm::vec3& up) const;
private:
static glm::vec2 GetBobbingOffset(float t, float amplitude);
};