|
1 | 1 | #include "player-movement-system.hpp" |
2 | 2 |
|
| 3 | +#include <components/collider.hpp> |
| 4 | + |
3 | 5 | #include "collision-system.hpp" |
4 | 6 |
|
5 | 7 | namespace gameplay { |
@@ -58,14 +60,42 @@ namespace gameplay { |
58 | 60 | } |
59 | 61 |
|
60 | 62 | void PlayerMovementSystem::handleDashing(PlayerMovementComponent* movement, glm::vec3& playerPosition, |
61 | | - our::Keyboard& keyboard, const glm::vec3& frontXZ) { |
| 63 | + our::Keyboard& keyboard, const glm::vec3& frontXZ, |
| 64 | + const glm::vec3& moveDir) { |
62 | 65 | if (keyboard.justPressed(GLFW_KEY_Q) && movement->dashCooldownTimer <= 0) { |
63 | 66 | glm::vec3 dashDirection = glm::normalize(frontXZ); |
64 | | - if (glm::length(movement->velocity) > 0.001f) { |
65 | | - // dash along moving direction if not stationary |
66 | | - dashDirection = glm::normalize(movement->velocity); |
| 67 | + if (glm::length(moveDir) > 0.001f) { |
| 68 | + // Dash along active WASD input direction (not velocity, which may still be decaying) |
| 69 | + dashDirection = glm::normalize(moveDir); |
67 | 70 | } |
68 | | - playerPosition += dashDirection * movement->dashDistance; |
| 71 | + |
| 72 | + // Sphere sweep to prevent tunneling through walls |
| 73 | + float actualDashDistance = movement->dashDistance; |
| 74 | + if (collisionSystem) { |
| 75 | + float capsuleRadius = 0.5f; |
| 76 | + float capsuleHeight = 1.0f; |
| 77 | + if (ColliderComponent* collider = movement->getOwner()->getComponent<ColliderComponent>()) { |
| 78 | + capsuleRadius = collider->radius; |
| 79 | + capsuleHeight = collider->height; |
| 80 | + } |
| 81 | + |
| 82 | + // Sweep from body center |
| 83 | + glm::vec3 bodyCenter = playerPosition; |
| 84 | + bodyCenter.y = movement->groundLevel + capsuleHeight * 0.5f; |
| 85 | + |
| 86 | + glm::vec3 sweepEnd = bodyCenter + dashDirection * movement->dashDistance; |
| 87 | + |
| 88 | + HitInfo hit = |
| 89 | + collisionSystem->sphereCast(bodyCenter, sweepEnd, capsuleRadius, CollisionLayer::LAYER_ENVIRONMENT); |
| 90 | + |
| 91 | + if (hit.hit) { |
| 92 | + // Small skin width to avoid ending flush against the wall (which would cause push-back) |
| 93 | + constexpr float SKIN_WIDTH = 0.05f; |
| 94 | + actualDashDistance = glm::max(0.0f, hit.distance - SKIN_WIDTH); |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + playerPosition += dashDirection * actualDashDistance; |
69 | 99 | movement->dashCooldownTimer = movement->dashCooldown; |
70 | 100 | movement->dashTriggeredThisFrame = true; |
71 | 101 | } |
@@ -176,7 +206,7 @@ namespace gameplay { |
176 | 206 |
|
177 | 207 | playerPosition += movement->velocity * deltaTime; |
178 | 208 |
|
179 | | - handleDashing(movement, playerPosition, keyboard, frontXZ); |
| 209 | + handleDashing(movement, playerPosition, keyboard, frontXZ, moveDir); |
180 | 210 | handleJumpingAndGravity(movement, playerPosition, keyboard, deltaTime); |
181 | 211 | handleHeightInterpolation(movement, playerPosition, deltaTime); |
182 | 212 | } |
|
0 commit comments