Skip to content

Commit 1e2b574

Browse files
fix: player dashing into objects or outside the map (#70)
Co-authored-by: LoayAhmed304 <loayahmed304@gmail.com>
1 parent 8a8186e commit 1e2b574

4 files changed

Lines changed: 75 additions & 7 deletions

File tree

src/game/systems/collision-system.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,40 @@ namespace gameplay {
296296
return hitInfo;
297297
}
298298

299+
// On-demand function
300+
HitInfo CollisionSystem::sphereCast(const glm::vec3& from, const glm::vec3& to, float radius,
301+
short targetLayer) const {
302+
HitInfo hitInfo;
303+
if (!collisionWorld) return hitInfo;
304+
305+
btSphereShape sphere(radius);
306+
307+
btTransform fromT;
308+
fromT.setIdentity();
309+
fromT.setOrigin(glmToBtVec3(from));
310+
311+
btTransform toT;
312+
toT.setIdentity();
313+
toT.setOrigin(glmToBtVec3(to));
314+
315+
btCollisionWorld::ClosestConvexResultCallback callback(glmToBtVec3(from), glmToBtVec3(to));
316+
callback.m_collisionFilterGroup = btBroadphaseProxy::AllFilter;
317+
callback.m_collisionFilterMask = targetLayer;
318+
319+
collisionWorld->convexSweepTest(&sphere, fromT, toT, callback);
320+
321+
if (callback.hasHit()) {
322+
hitInfo.hit = true;
323+
hitInfo.point = btToGlmVec3(callback.m_hitPointWorld);
324+
hitInfo.normal = btToGlmVec3(callback.m_hitNormalWorld);
325+
hitInfo.entity = static_cast<our::Entity*>(callback.m_hitCollisionObject->getUserPointer());
326+
float totalDistance = glm::length(to - from);
327+
hitInfo.distance = callback.m_closestHitFraction * totalDistance;
328+
}
329+
330+
return hitInfo;
331+
}
332+
299333
// On-demand function
300334
std::vector<our::Entity*> CollisionSystem::overlapSphere(const glm::vec3& center, float radius, short targetLayer) {
301335
std::vector<our::Entity*> results;

src/game/systems/collision-system.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ namespace gameplay {
9797
HitInfo raycast(const Ray& ray, float maxDistance,
9898
const short targetLayer = CollisionLayer::LAYER_ENVIRONMENT) const;
9999

100+
// On-demand sphere sweep (convex cast) that sweeps a sphere from 'from' to 'to'.
101+
HitInfo sphereCast(const glm::vec3& from, const glm::vec3& to, float radius,
102+
short targetLayer = CollisionLayer::LAYER_ENVIRONMENT) const;
103+
100104
// On-demand overlap sphere function that can be used outside of the update loop
101105
std::vector<our::Entity*> overlapSphere(const glm::vec3& center, float radius, short targetLayer);
102106

src/game/systems/player-movement-system.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "player-movement-system.hpp"
22

3+
#include <components/collider.hpp>
4+
35
#include "collision-system.hpp"
46

57
namespace gameplay {
@@ -58,14 +60,42 @@ namespace gameplay {
5860
}
5961

6062
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) {
6265
if (keyboard.justPressed(GLFW_KEY_Q) && movement->dashCooldownTimer <= 0) {
6366
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);
6770
}
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;
6999
movement->dashCooldownTimer = movement->dashCooldown;
70100
movement->dashTriggeredThisFrame = true;
71101
}
@@ -176,7 +206,7 @@ namespace gameplay {
176206

177207
playerPosition += movement->velocity * deltaTime;
178208

179-
handleDashing(movement, playerPosition, keyboard, frontXZ);
209+
handleDashing(movement, playerPosition, keyboard, frontXZ, moveDir);
180210
handleJumpingAndGravity(movement, playerPosition, keyboard, deltaTime);
181211
handleHeightInterpolation(movement, playerPosition, deltaTime);
182212
}

src/game/systems/player-movement-system.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace gameplay {
1818
const glm::vec3& moveDir, float deltaTime, float slideStartSpeed);
1919
void handleGroundedMovement(PlayerMovementComponent* movement, const glm::vec3& moveDir, float deltaTime);
2020
void handleDashing(PlayerMovementComponent* movement, glm::vec3& playerPosition, our::Keyboard& keyboard,
21-
const glm::vec3& frontXZ);
21+
const glm::vec3& frontXZ, const glm::vec3& moveDir);
2222
void handleJumpingAndGravity(PlayerMovementComponent* movement, glm::vec3& playerPosition,
2323
our::Keyboard& keyboard, float deltaTime);
2424
void handleHeightInterpolation(PlayerMovementComponent* movement, glm::vec3& playerPosition, float deltaTime);

0 commit comments

Comments
 (0)