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), pitch_(0.0f),
input_(0), input_(0),
cam_forward_(0.0f), 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_); float pitch_sin = glm::sin(pitch_);
// MOVEMENT // MOVEMENT
glm::vec2 velocity_xy(0.0f); glm::vec2 desire_xy(0.0f);
if (input_ & PI_FORWARD) if (input_ & PI_FORWARD)
velocity_xy.y += 1.0f; desire_xy.y += 1.0f;
if (input_ & PI_BACKWARD) if (input_ & PI_BACKWARD)
velocity_xy.y -= 1.0f; desire_xy.y -= 1.0f;
if (input_ & PI_LEFT) if (input_ & PI_LEFT)
velocity_xy.x -= 1.0f; desire_xy.x -= 1.0f;
if (input_ & PI_RIGHT) if (input_ & PI_RIGHT)
velocity_xy.x += 1.0f; desire_xy.x += 1.0f;
glm::mat2 movement_basis( glm::mat2 movement_basis(
yaw_cos, -yaw_sin, yaw_cos, -yaw_sin,
yaw_sin, yaw_cos yaw_sin, yaw_cos
); );
float speed = 3.0f; // Base speed if (glm::length(desire_xy) > 0.01f)
glm::vec2 normalized_velocity_xy(0.0f);
if (glm::length(velocity_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( glm::vec3 velocity = glm::vec3(
normalized_velocity_xy * speed, velocity_xy,
-1.0f // No vertical movement for now -1.0f // No vertical movement for now
); );
@ -75,14 +101,52 @@ void game::Player::Update(float dt)
const glm::mat3& occu_basis = occu_->GetBasis(); const glm::mat3& occu_basis = occu_->GetBasis();
cam_forward_ = occu_basis * glm::vec3(yaw_sin * pitch_cos, yaw_cos * pitch_cos, pitch_sin); 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_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 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(); 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_; forward = cam_forward_;
up = cam_up_; 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 // in occu's sector space
glm::vec3 cam_forward_; glm::vec3 cam_forward_;
glm::vec3 cam_right_;
glm::vec3 cam_up_; 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: public:
Player(World* world, size_t sector_idx, const glm::vec3& position); 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; 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);
}; };