From 76a16a214e592a0766b6b15d3b2e34ca7f2f5d42 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 2 Feb 2026 23:10:19 -0800 Subject: [PATCH] Improve movement, crouching, and add M2 animation Movement: - Fix speed controls: Shift=sprint (28), normal run (14), Ctrl=walk (5) - Reduce character height for doorway clearance (eye height 1.2) - Add working crouch (C or X key) with smooth transition (eye height 0.6) - Jump to stand up from crouch M2 Animation: - Add animation time tracking per M2 instance - Add procedural swaying animation in vertex shader - Update animation each frame for vegetation movement --- include/rendering/camera_controller.hpp | 13 +++++++----- include/rendering/m2_renderer.hpp | 11 ++++++++++ src/rendering/camera_controller.cpp | 23 ++++++++++++-------- src/rendering/m2_renderer.cpp | 28 ++++++++++++++++++++++--- src/rendering/renderer.cpp | 5 +++++ 5 files changed, 63 insertions(+), 17 deletions(-) diff --git a/include/rendering/camera_controller.hpp b/include/rendering/camera_controller.hpp index e4d36d84..a71fe7cf 100644 --- a/include/rendering/camera_controller.hpp +++ b/include/rendering/camera_controller.hpp @@ -85,7 +85,9 @@ private: // Gravity / grounding float verticalVelocity = 0.0f; bool grounded = false; - float eyeHeight = 1.8f; // WoW human eye height (~2 yard tall character) + static constexpr float STAND_EYE_HEIGHT = 1.2f; // Standing eye height + static constexpr float CROUCH_EYE_HEIGHT = 0.6f; // Crouching eye height + float eyeHeight = STAND_EYE_HEIGHT; float lastGroundZ = 0.0f; // Last known ground height (fallback when no terrain) static constexpr float GRAVITY = -30.0f; static constexpr float JUMP_VELOCITY = 15.0f; @@ -115,11 +117,12 @@ private: // Movement callback MovementCallback movementCallback; - // Movement speeds (scaled up for better feel) + // Movement speeds bool useWoWSpeed = false; - static constexpr float WOW_RUN_SPEED = 14.0f; // Double base WoW speed for responsiveness - static constexpr float WOW_WALK_SPEED = 5.0f; // Walk (hold Shift) - static constexpr float WOW_BACK_SPEED = 9.0f; // Backpedal + static constexpr float WOW_RUN_SPEED = 14.0f; // Normal run (WASD) + static constexpr float WOW_SPRINT_SPEED = 28.0f; // Sprint (hold Shift) + static constexpr float WOW_WALK_SPEED = 5.0f; // Walk (hold Ctrl) + static constexpr float WOW_BACK_SPEED = 9.0f; // Backpedal static constexpr float WOW_GRAVITY = -19.29f; static constexpr float WOW_JUMP_VELOCITY = 7.96f; diff --git a/include/rendering/m2_renderer.hpp b/include/rendering/m2_renderer.hpp index 6735f991..66f36ebf 100644 --- a/include/rendering/m2_renderer.hpp +++ b/include/rendering/m2_renderer.hpp @@ -57,6 +57,11 @@ struct M2Instance { float scale; glm::mat4 modelMatrix; + // Animation state + float animTime = 0.0f; // Current animation time + float animSpeed = 1.0f; // Animation playback speed + uint32_t animId = 0; // Current animation sequence + void updateModelMatrix(); }; @@ -100,6 +105,12 @@ public: uint32_t createInstanceWithMatrix(uint32_t modelId, const glm::mat4& modelMatrix, const glm::vec3& position); + /** + * Update animation state for all instances + * @param deltaTime Time since last frame + */ + void update(float deltaTime); + /** * Render all visible instances */ diff --git a/src/rendering/camera_controller.cpp b/src/rendering/camera_controller.cpp index 8c24743f..51e4891a 100644 --- a/src/rendering/camera_controller.cpp +++ b/src/rendering/camera_controller.cpp @@ -41,13 +41,15 @@ void CameraController::update(float deltaTime) { // Calculate movement speed based on direction and modifiers float speed; if (useWoWSpeed) { - // WoW-correct speeds + // Movement speeds (Shift = sprint, Ctrl = walk) if (nowBackward && !nowForward) { speed = WOW_BACK_SPEED; } else if (!uiWantsKeyboard && (input.isKeyPressed(SDL_SCANCODE_LSHIFT) || input.isKeyPressed(SDL_SCANCODE_RSHIFT))) { - speed = WOW_WALK_SPEED; // Shift = walk in WoW mode + speed = WOW_SPRINT_SPEED; // Shift = sprint (faster) + } else if (!uiWantsKeyboard && (input.isKeyPressed(SDL_SCANCODE_LCTRL) || input.isKeyPressed(SDL_SCANCODE_RCTRL))) { + speed = WOW_WALK_SPEED; // Ctrl = walk (slower) } else { - speed = WOW_RUN_SPEED; + speed = WOW_RUN_SPEED; // Normal run } } else { // Exploration mode (original behavior) @@ -69,13 +71,18 @@ void CameraController::update(float deltaTime) { right = glm::normalize(right); } - // Toggle sit with X key (edge-triggered) — only when UI doesn't want keyboard - bool xDown = !uiWantsKeyboard && input.isKeyPressed(SDL_SCANCODE_X); + // Toggle sit/crouch with X or C key (edge-triggered) — only when UI doesn't want keyboard + bool xDown = !uiWantsKeyboard && (input.isKeyPressed(SDL_SCANCODE_X) || input.isKeyPressed(SDL_SCANCODE_C)); if (xDown && !xKeyWasDown) { sitting = !sitting; } xKeyWasDown = xDown; + // Update eye height based on crouch state (smooth transition) + float targetEyeHeight = sitting ? CROUCH_EYE_HEIGHT : STAND_EYE_HEIGHT; + float heightLerpSpeed = 10.0f * deltaTime; + eyeHeight = eyeHeight + (targetEyeHeight - eyeHeight) * std::min(1.0f, heightLerpSpeed); + // Calculate horizontal movement vector glm::vec3 movement(0.0f); @@ -84,10 +91,8 @@ void CameraController::update(float deltaTime) { if (nowStrafeLeft) movement -= right; if (nowStrafeRight) movement += right; - // Stand up if any movement key is pressed while sitting - if (!uiWantsKeyboard && sitting && (input.isKeyPressed(SDL_SCANCODE_W) || input.isKeyPressed(SDL_SCANCODE_S) || - input.isKeyPressed(SDL_SCANCODE_A) || input.isKeyPressed(SDL_SCANCODE_D) || - input.isKeyPressed(SDL_SCANCODE_SPACE))) { + // Stand up if jumping while crouched + if (!uiWantsKeyboard && sitting && input.isKeyPressed(SDL_SCANCODE_SPACE)) { sitting = false; } diff --git a/src/rendering/m2_renderer.cpp b/src/rendering/m2_renderer.cpp index 1926bee4..7b5eaa5c 100644 --- a/src/rendering/m2_renderer.cpp +++ b/src/rendering/m2_renderer.cpp @@ -37,7 +37,7 @@ bool M2Renderer::initialize(pipeline::AssetManager* assets) { LOG_INFO("Initializing M2 renderer..."); - // Create M2 shader + // Create M2 shader with simple animation support const char* vertexSrc = R"( #version 330 core layout (location = 0) in vec3 aPos; @@ -47,15 +47,27 @@ bool M2Renderer::initialize(pipeline::AssetManager* assets) { uniform mat4 uModel; uniform mat4 uView; uniform mat4 uProjection; + uniform float uTime; + uniform float uAnimScale; // 0 = no animation, 1 = full animation out vec3 FragPos; out vec3 Normal; out vec2 TexCoord; void main() { - vec4 worldPos = uModel * vec4(aPos, 1.0); + vec3 pos = aPos; + + // Simple swaying animation for vegetation/doodads + // Only animate vertices above ground level (positive Y in model space) + if (uAnimScale > 0.0 && pos.z > 0.5) { + float sway = sin(uTime * 2.0 + pos.x * 0.5 + pos.y * 0.3) * 0.1; + float heightFactor = clamp((pos.z - 0.5) / 3.0, 0.0, 1.0); + pos.x += sway * heightFactor * uAnimScale; + pos.y += sway * 0.5 * heightFactor * uAnimScale; + } + + vec4 worldPos = uModel * vec4(pos, 1.0); FragPos = worldPos.xyz; - // Use mat3(uModel) directly - avoids expensive inverse() per vertex Normal = mat3(uModel) * aNormal; TexCoord = aTexCoord; @@ -302,12 +314,20 @@ uint32_t M2Renderer::createInstanceWithMatrix(uint32_t modelId, const glm::mat4& instance.rotation = glm::vec3(0.0f); instance.scale = 1.0f; instance.modelMatrix = modelMatrix; + instance.animTime = static_cast(rand()) / RAND_MAX * 10.0f; // Random start time instances.push_back(instance); return instance.id; } +void M2Renderer::update(float deltaTime) { + // Advance animation time for all instances + for (auto& instance : instances) { + instance.animTime += deltaTime * instance.animSpeed; + } +} + void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm::mat4& projection) { (void)camera; // unused for now @@ -371,6 +391,8 @@ void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm:: } shader->setUniform("uModel", instance.modelMatrix); + shader->setUniform("uTime", instance.animTime); + shader->setUniform("uAnimScale", 1.0f); // Enable animation for all M2s glBindVertexArray(model.vao); diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index e3d0acf1..ac03ef30 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -569,6 +569,11 @@ void Renderer::update(float deltaTime) { characterRenderer->update(deltaTime); } + // Update M2 doodad animations + if (m2Renderer) { + m2Renderer->update(deltaTime); + } + // Update zone detection and music if (zoneManager && musicManager && terrainManager && camera) { // First check tile-based zone