Skip to content

Commit baa0ad2

Browse files
committed
refactor: split movement into functions
1 parent e8dde3a commit baa0ad2

3 files changed

Lines changed: 162 additions & 134 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ add_executable(${PROJECT_NAME}
151151
src/game/components/player.cpp
152152
src/game/game-registration.cpp
153153
src/game/components/player-movement.cpp
154+
src/game/systems/player-movement-system.cpp
154155

155156
src/common/systems/forward-renderer.cpp
156157
)
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#include "player-movement-system.hpp"
2+
3+
namespace gameplay {
4+
5+
void PlayerMovementSystem::handleSlidingAndCrouching(PlayerMovementComponent* movement, our::Keyboard& keyboard, const glm::vec3& moveDir, float deltaTime, float slideStartSpeed) {
6+
bool crouchPressed = keyboard.justPressed(GLFW_KEY_LEFT_CONTROL);
7+
8+
if (movement->isSliding) {
9+
movement->slideTimer -= deltaTime;
10+
if (movement->slideTimer <= 0) {
11+
movement->isSliding = false;
12+
movement->isCrouching = true;
13+
movement->slideCooldownTimer = movement->slideCooldown;
14+
} else {
15+
// quadratically decays from slideStartSpeed to crouchSpeed
16+
float t = movement->slideTimer / movement->slideDuration; // goes from 1 to 0 and used for the decay curve in speed when sliding
17+
float speed = movement->crouchSpeed + (slideStartSpeed - movement->crouchSpeed) * (t * t);
18+
movement->velocity = glm::normalize(movement->velocity) * speed;
19+
}
20+
} else if (crouchPressed) {
21+
if (movement->isSprinting && glm::length(moveDir) > 0.001f && movement->slideCooldownTimer <= 0) {
22+
movement->isSliding = true;
23+
movement->slideTimer = movement->slideDuration;
24+
movement->velocity = moveDir * slideStartSpeed; // preserves momentum when sliding and keys are released
25+
movement->isCrouching = false;
26+
} else {
27+
movement->isCrouching = !movement->isCrouching;
28+
}
29+
}
30+
}
31+
32+
void PlayerMovementSystem::handleGroundedMovement(PlayerMovementComponent* movement, const glm::vec3& moveDir, float deltaTime) {
33+
if (!movement->isSliding && movement->isGrounded) {
34+
float currentSpeed = movement->walkSpeed;
35+
if (movement->isSprinting) {
36+
movement->isCrouching = false; // sprinting cancels crouching
37+
currentSpeed *= movement->sprintMultiplier;
38+
} else if (movement->isCrouching) {
39+
currentSpeed = movement->crouchSpeed;
40+
}
41+
42+
if (glm::length(moveDir) > 0.001f) {
43+
movement->velocity = moveDir * currentSpeed;
44+
} else {
45+
// acts like friction so stopping after key release is not so stiff
46+
movement->velocity *= glm::max(0.0f, 1.0f - 10.0f * deltaTime);
47+
if (glm::length(movement->velocity) < 0.1f) movement->velocity = glm::vec3(0);
48+
}
49+
}
50+
}
51+
52+
void PlayerMovementSystem::handleDashing(PlayerMovementComponent* movement, our::Entity* playerEntity, glm::vec3& playerPosition, our::Keyboard& keyboard, const glm::vec3& frontXZ, float deltaTime) {
53+
if (keyboard.justPressed(GLFW_KEY_Q) && movement->dashCooldownTimer <= 0) {
54+
glm::vec3 dashDirection = glm::normalize(frontXZ);
55+
if (glm::length(movement->velocity) > 0.001f) {
56+
// dash along moving direction if not stationary
57+
dashDirection = glm::normalize(movement->velocity);
58+
}
59+
playerPosition += dashDirection * movement->dashDistance;
60+
movement->dashCooldownTimer = movement->dashCooldown;
61+
dashEffectTimer = DASH_EFFECT_DURATION;
62+
}
63+
64+
if (dashEffectTimer > 0) dashEffectTimer -= deltaTime;
65+
if (auto* effects = playerEntity->getComponent<PostProcessEffectsComponent>()) {
66+
effects->uniforms["intensity"] = glm::max(0.0f, dashEffectTimer / DASH_EFFECT_DURATION);
67+
}
68+
}
69+
70+
void PlayerMovementSystem::handleJumpingAndGravity(PlayerMovementComponent* movement, glm::vec3& playerPosition, our::Keyboard& keyboard, float deltaTime) {
71+
if (keyboard.justPressed(GLFW_KEY_SPACE) && movement->isGrounded) {
72+
if (movement->isSliding) {
73+
movement->slideCooldownTimer = movement->slideCooldown;
74+
}
75+
movement->isSliding = false; // jumping cancels crouching / sliding
76+
movement->isCrouching = false;
77+
movement->verticalVelocity = movement->jumpForce;
78+
movement->isGrounded = false;
79+
}
80+
81+
if (!movement->isGrounded) {
82+
movement->verticalVelocity -= movement->gravity * deltaTime;
83+
playerPosition.y += movement->verticalVelocity * deltaTime;
84+
85+
// jumping always goes back to standing height
86+
float minY = movement->verticalVelocity < 0 ? movement->groundLevel + movement->playerHeight
87+
: movement->groundLevel + movement->crouchHeight;
88+
if (playerPosition.y <= minY) {
89+
playerPosition.y = minY;
90+
movement->verticalVelocity = 0.0f;
91+
movement->isGrounded = true;
92+
}
93+
}
94+
}
95+
96+
void PlayerMovementSystem::handleHeightInterpolation(PlayerMovementComponent* movement, glm::vec3& playerPosition, float deltaTime) {
97+
if (movement->isGrounded) {
98+
float targetHeight =
99+
(movement->isCrouching || movement->isSliding) ? movement->crouchHeight : movement->playerHeight;
100+
float currentHeight = playerPosition.y - movement->groundLevel;
101+
float lerpedHeight = currentHeight + (targetHeight - currentHeight) * glm::min(1.0f, 10.0f * deltaTime);
102+
playerPosition.y = movement->groundLevel + lerpedHeight;
103+
}
104+
}
105+
106+
void PlayerMovementSystem::update(our::World* world, float deltaTime, our::Application* app) {
107+
PlayerMovementComponent* movement = nullptr;
108+
for (our::Entity* entity : world->getEntities()) {
109+
movement = entity->getComponent<PlayerMovementComponent>();
110+
if (movement) break;
111+
}
112+
113+
if (!movement) return;
114+
115+
our::Entity* playerEntity = movement->getOwner();
116+
glm::vec3& playerPosition = playerEntity->localTransform.position;
117+
118+
our::Keyboard& keyboard = app->getKeyboard();
119+
120+
if (movement->slideCooldownTimer > 0) movement->slideCooldownTimer -= deltaTime;
121+
if (movement->dashCooldownTimer > 0) movement->dashCooldownTimer -= deltaTime;
122+
123+
glm::mat4 M = playerEntity->localTransform.toMat4();
124+
glm::vec3 front = glm::vec3(M * glm::vec4(0, 0, -1, 0));
125+
glm::vec3 right = glm::vec3(M * glm::vec4(1, 0, 0, 0));
126+
glm::vec3 frontXZ = glm::normalize(glm::vec3(front.x, 0, front.z));
127+
glm::vec3 rightXZ = glm::normalize(glm::vec3(right.x, 0, right.z));
128+
129+
glm::vec3 moveDir(0);
130+
if (keyboard.isPressed(GLFW_KEY_W)) moveDir += frontXZ;
131+
if (keyboard.isPressed(GLFW_KEY_S)) moveDir -= frontXZ;
132+
if (keyboard.isPressed(GLFW_KEY_D)) moveDir += rightXZ;
133+
if (keyboard.isPressed(GLFW_KEY_A)) moveDir -= rightXZ;
134+
if (glm::length(moveDir) > 0.001f) moveDir = glm::normalize(moveDir);
135+
136+
movement->isSprinting = keyboard.isPressed(GLFW_KEY_LEFT_SHIFT) && !movement->isSliding;
137+
138+
float sprintSpeed = movement->walkSpeed * movement->sprintMultiplier;
139+
float slideStartSpeed = sprintSpeed * movement->slideSpeedMultiplier;
140+
141+
handleSlidingAndCrouching(movement, keyboard, moveDir, deltaTime, slideStartSpeed);
142+
handleGroundedMovement(movement, moveDir, deltaTime);
143+
144+
playerPosition += movement->velocity * deltaTime;
145+
146+
handleDashing(movement, playerEntity, playerPosition, keyboard, frontXZ, deltaTime);
147+
handleJumpingAndGravity(movement, playerPosition, keyboard, deltaTime);
148+
handleHeightInterpolation(movement, playerPosition, deltaTime);
149+
}
150+
151+
} // namespace gameplay
Lines changed: 10 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
#pragma once
22

33
#include <application.hpp>
4-
#include <components/camera.hpp>
4+
#include <components/player-movement.hpp>
5+
#include <components/post-process-effects.hpp>
56
#include <ecs/world.hpp>
67
#include <glm/glm.hpp>
7-
#include <glm/gtc/constants.hpp>
8-
#include <glm/trigonometric.hpp>
9-
10-
#include "GLFW/glfw3.h"
11-
#include "components/player-movement.hpp"
12-
#include "components/post-process-effects.hpp"
13-
#include "glm/fwd.hpp"
14-
#include "input/keyboard.hpp"
8+
#include <input/keyboard.hpp>
159

1610
namespace gameplay {
1711

@@ -21,132 +15,14 @@ namespace gameplay {
2115
float dashEffectTimer = 0.0f;
2216
static constexpr float DASH_EFFECT_DURATION = 0.3f;
2317

24-
public:
25-
void update(our::World* world, float deltaTime, our::Application* app) {
26-
PlayerMovementComponent* movement = nullptr;
27-
for (auto entity : world->getEntities()) {
28-
movement = entity->getComponent<PlayerMovementComponent>();
29-
if (movement) break;
30-
}
31-
32-
if (!movement) return;
33-
34-
our::Entity* playerEntity = movement->getOwner();
35-
glm::vec3& playerPosition = playerEntity->localTransform.position;
36-
37-
our::Keyboard& keyboard = app->getKeyboard();
38-
39-
if (movement->slideCooldownTimer > 0) movement->slideCooldownTimer -= deltaTime;
40-
if (movement->dashCooldownTimer > 0) movement->dashCooldownTimer -= deltaTime;
41-
42-
glm::mat4 M = playerEntity->localTransform.toMat4();
43-
glm::vec3 front = glm::vec3(M * glm::vec4(0, 0, -1, 0));
44-
glm::vec3 right = glm::vec3(M * glm::vec4(1, 0, 0, 0));
45-
glm::vec3 frontXZ = glm::normalize(glm::vec3(front.x, 0, front.z));
46-
glm::vec3 rightXZ = glm::normalize(glm::vec3(right.x, 0, right.z));
47-
48-
glm::vec3 moveDir(0);
49-
if (keyboard.isPressed(GLFW_KEY_W)) moveDir += frontXZ;
50-
if (keyboard.isPressed(GLFW_KEY_S)) moveDir -= frontXZ;
51-
if (keyboard.isPressed(GLFW_KEY_D)) moveDir += rightXZ;
52-
if (keyboard.isPressed(GLFW_KEY_A)) moveDir -= rightXZ;
53-
if (glm::length(moveDir) > 0.001f) moveDir = glm::normalize(moveDir);
54-
55-
movement->isSprinting = keyboard.isPressed(GLFW_KEY_LEFT_SHIFT) && !movement->isSliding;
56-
bool crouchPressed = keyboard.justPressed(GLFW_KEY_LEFT_CONTROL);
57-
float sprintSpeed = movement->walkSpeed * movement->sprintMultiplier;
58-
float slideStartSpeed = sprintSpeed * movement->slideSpeedMultiplier;
18+
void handleSlidingAndCrouching(PlayerMovementComponent* movement, our::Keyboard& keyboard, const glm::vec3& moveDir, float deltaTime, float slideStartSpeed);
19+
void handleGroundedMovement(PlayerMovementComponent* movement, const glm::vec3& moveDir, float deltaTime);
20+
void handleDashing(PlayerMovementComponent* movement, our::Entity* playerEntity, glm::vec3& playerPosition, our::Keyboard& keyboard, const glm::vec3& frontXZ, float deltaTime);
21+
void handleJumpingAndGravity(PlayerMovementComponent* movement, glm::vec3& playerPosition, our::Keyboard& keyboard, float deltaTime);
22+
void handleHeightInterpolation(PlayerMovementComponent* movement, glm::vec3& playerPosition, float deltaTime);
5923

60-
if (movement->isSliding) {
61-
movement->slideTimer -= deltaTime;
62-
if (movement->slideTimer <= 0) {
63-
movement->isSliding = false;
64-
movement->isCrouching = true;
65-
movement->slideCooldownTimer = movement->slideCooldown;
66-
} else {
67-
// quadratically decays from slideStartSpeed to crouchSpeed
68-
float t = movement->slideTimer / movement->slideDuration;
69-
float speed = movement->crouchSpeed + (slideStartSpeed - movement->crouchSpeed) * (t * t);
70-
movement->velocity = glm::normalize(movement->velocity) * speed;
71-
}
72-
} else if (crouchPressed) {
73-
if (movement->isSprinting && glm::length(moveDir) > 0.001f && movement->slideCooldownTimer <= 0) {
74-
movement->isSliding = true;
75-
movement->slideTimer = movement->slideDuration;
76-
movement->velocity =
77-
moveDir * slideStartSpeed; // preserves momentum when sliding and keys are released
78-
movement->isCrouching = false;
79-
} else {
80-
movement->isCrouching = !movement->isCrouching;
81-
}
82-
}
83-
if (!movement->isSliding && movement->isGrounded) {
84-
float currentSpeed = movement->walkSpeed;
85-
if (movement->isSprinting) {
86-
movement->isCrouching = false;
87-
currentSpeed *= movement->sprintMultiplier;
88-
} else if (movement->isCrouching) {
89-
currentSpeed = movement->crouchSpeed;
90-
}
91-
92-
if (glm::length(moveDir) > 0.001f) {
93-
movement->velocity = moveDir * currentSpeed;
94-
} else {
95-
// acts like friction so stopping after key release is not so stiff
96-
movement->velocity *= glm::max(0.0f, 1.0f - 10.0f * deltaTime);
97-
if (glm::length(movement->velocity) < 0.1f) movement->velocity = glm::vec3(0);
98-
}
99-
}
100-
101-
playerPosition += movement->velocity * deltaTime;
102-
103-
if (keyboard.justPressed(GLFW_KEY_Q) && movement->dashCooldownTimer <= 0) {
104-
glm::vec3 dashDirection = glm::normalize(frontXZ);
105-
if (glm::length(movement->velocity) > 0.001f) {
106-
// dash along moving direction if not stationary
107-
dashDirection = glm::normalize(movement->velocity);
108-
}
109-
playerPosition += dashDirection * movement->dashDistance;
110-
movement->dashCooldownTimer = movement->dashCooldown;
111-
dashEffectTimer = DASH_EFFECT_DURATION;
112-
}
113-
114-
if (dashEffectTimer > 0) dashEffectTimer -= deltaTime;
115-
if (auto* effects = playerEntity->getComponent<PostProcessEffectsComponent>()) {
116-
effects->uniforms["intensity"] = glm::max(0.0f, dashEffectTimer / DASH_EFFECT_DURATION);
117-
}
118-
if (keyboard.justPressed(GLFW_KEY_SPACE) && movement->isGrounded) {
119-
if (movement->isSliding) {
120-
movement->slideCooldownTimer = movement->slideCooldown;
121-
}
122-
movement->isSliding = false;
123-
movement->isCrouching = false;
124-
movement->verticalVelocity = movement->jumpForce;
125-
movement->isGrounded = false;
126-
}
127-
128-
if (!movement->isGrounded) {
129-
movement->verticalVelocity -= movement->gravity * deltaTime;
130-
playerPosition.y += movement->verticalVelocity * deltaTime;
131-
132-
// jumping always goes back to standing height
133-
float minY = movement->verticalVelocity < 0 ? movement->groundLevel + movement->playerHeight
134-
: movement->groundLevel + movement->crouchHeight;
135-
if (playerPosition.y <= minY) {
136-
playerPosition.y = minY;
137-
movement->verticalVelocity = 0.0f;
138-
movement->isGrounded = true;
139-
}
140-
}
141-
142-
if (movement->isGrounded) {
143-
float targetHeight =
144-
(movement->isCrouching || movement->isSliding) ? movement->crouchHeight : movement->playerHeight;
145-
float currentHeight = playerPosition.y - movement->groundLevel;
146-
float lerpedHeight = currentHeight + (targetHeight - currentHeight) * glm::min(1.0f, 10.0f * deltaTime);
147-
playerPosition.y = movement->groundLevel + lerpedHeight;
148-
}
149-
}
24+
public:
25+
void update(our::World* world, float deltaTime, our::Application* app);
15026
};
15127

15228
} // namespace gameplay

0 commit comments

Comments
 (0)