Skip to content

Commit 80c4957

Browse files
authored
feat: player movement (#32)
* refactor: remove translation logic from free camera controller * feat: add player movement component * feat: add player movement system * feat: add jumping to player movement * feat: improve sliding and allow jumping while sliding, make height lerped from and to crouch * feat: add a post process shader on dash to give a sense of speed * chore: format * fix: sprinting cancels crouching * chore: remove redundant camera check * refactor: split movement into functions * refactor: add postprocesssystem for gameplay driven post process shaders, and move postprocesscomponent from game to common * format
1 parent e82b339 commit 80c4957

15 files changed

Lines changed: 412 additions & 46 deletions

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ add_executable(${PROJECT_NAME}
265265
src/game/game-registration.cpp
266266
src/game/systems/collision-system.cpp
267267
src/game/systems/collision-debug-drawer.cpp
268+
src/game/components/player-movement.cpp
269+
src/game/systems/player-movement-system.cpp
268270

269271
src/common/systems/forward-renderer.cpp
270272
src/common/systems/audio-system.cpp
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#version 330
2+
3+
uniform sampler2D tex;
4+
uniform float intensity;
5+
6+
in vec2 tex_coord;
7+
out vec4 frag_color;
8+
9+
#define BLUR_SAMPLES 8
10+
11+
void main() {
12+
vec2 center = vec2(0.5);
13+
vec2 dir = tex_coord - center;
14+
15+
// Radial Zoom Blur
16+
vec3 color = vec3(0.0);
17+
float blurStrength = intensity * 0.2;
18+
for (int i = 0; i < BLUR_SAMPLES; i++) {
19+
float t = float(i) / float(BLUR_SAMPLES);
20+
vec2 offset = dir * blurStrength * t;
21+
color += texture(tex, tex_coord - offset).rgb;
22+
}
23+
color /= float(BLUR_SAMPLES);
24+
25+
// Chromatic Aberration
26+
float caStrength = intensity * 0.015;
27+
vec2 caDir = normalize(dir + vec2(0.001)) * caStrength;
28+
float r = texture(tex, tex_coord - caDir).r;
29+
float g = texture(tex, tex_coord).g;
30+
float b = texture(tex, tex_coord + caDir).b;
31+
vec3 caColor = vec3(r, g, b);
32+
33+
color = mix(color, caColor, 0.4);
34+
35+
// Vignette
36+
vec2 ndc = tex_coord * 2.0 - 1.0;
37+
float vignette = 1.0 / (1.0 + dot(ndc, ndc));
38+
color *= vignette;
39+
40+
frag_color = vec4(color, 1.0);
41+
}

config/app.jsonc

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"scene": {
1212
"renderer": {
1313
"sky": "assets/textures/sky.jpg",
14-
"postprocess": "assets/shaders/postprocess/vignette.frag"
14+
"postprocess": "assets/shaders/postprocess/dash-distortion.frag"
1515
},
1616
"assets": {
1717
"shaders": {
@@ -290,15 +290,32 @@
290290
},
291291
{
292292
"type": "Free Camera Controller",
293-
"positionSensitivity": [8.0, 0.0, 8.0],
294-
"rotationSensitivity": 0.008,
295-
"speedupFactor": 2.5,
293+
"rotationSensitivity": 0.01,
294+
"fovSensitivity": 0.3
295+
},
296+
{
297+
"type": "PlayerMovement",
298+
"walkSpeed": 8.0,
299+
"sprintMultiplier": 2.0,
300+
"crouchSpeed": 4.0,
301+
"crouchHeight": 1.0,
302+
"slideSpeedMultiplier": 1.5,
303+
"slideDuration": 0.8,
304+
"slideCooldown": 0.5,
305+
"dashDistance": 5.0,
306+
"dashCooldown": 1.0,
296307
"groundLevel": 0.0,
297-
"playerHeight": 1.8
308+
"playerHeight": 2,
309+
"jumpForce": 9.0
298310
},
299311
{
300312
"type": "Player"
301313
},
314+
{
315+
"type": "Post Process Effects Component"
316+
}
317+
],
318+
"children": [
302319
{
303320
"type": "Health",
304321
"maxHealth": 100.0
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
#include "free-camera-controller.hpp"
22

3-
#include "../deserialize-utils.hpp"
4-
#include "../ecs/entity.hpp"
5-
63
namespace our {
74
// Reads sensitivities & speedupFactor from the given json object
85
void FreeCameraControllerComponent::deserialize(const nlohmann::json& data) {
96
if (!data.is_object()) return;
107
rotationSensitivity = data.value("rotationSensitivity", rotationSensitivity);
118
fovSensitivity = data.value("fovSensitivity", fovSensitivity);
12-
positionSensitivity = data.value("positionSensitivity", positionSensitivity);
13-
speedupFactor = data.value("speedupFactor", speedupFactor);
14-
groundLevel = data.value("groundLevel", groundLevel);
15-
playerHeight = data.value("playerHeight", playerHeight);
169
}
1710
} // namespace our

src/common/components/free-camera-controller.hpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@ namespace our {
1616
// The senstivity paramter defined sensitive the camera rotation & fov is to the mouse moves and wheel scrolling
1717
float rotationSensitivity = 0.01f; // The angle change per pixel of mouse movement
1818
float fovSensitivity = 0.3f; // The fov angle change per unit of mouse wheel scrolling
19-
glm::vec3 positionSensitivity = {3.0f, 3.0f,
20-
3.0f}; // The unity per second of camera movement if WASD is pressed
21-
float speedupFactor = 5.0f; // A multiplier for the positionSensitivity if "Left Shift" is held.
22-
23-
// Ground collision
24-
float groundLevel = 0.0f;
25-
float playerHeight = 1.7f;
2619

2720
// The ID of this component type is "Free Camera Controller"
2821
static std::string getID() {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
3+
#include <ecs/component.hpp>
4+
#include <string>
5+
#include <unordered_map>
6+
7+
namespace our {
8+
9+
// values set by gameplay and read by the renderer for the active postprocess shader
10+
class PostProcessEffectsComponent : public Component {
11+
public:
12+
std::unordered_map<std::string, float> uniforms;
13+
14+
static std::string getID() {
15+
return "Post Process Effects Component";
16+
}
17+
18+
void deserialize(const nlohmann::json& data) override {}
19+
};
20+
21+
} // namespace our

src/common/systems/forward-renderer.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "forward-renderer.hpp"
22

33
#include "../components/model-renderer.hpp"
4+
#include "../components/post-process-effects.hpp"
45
#include "../mesh/mesh-utils.hpp"
56
#include "../texture/texture-utils.hpp"
67

@@ -280,6 +281,17 @@ namespace our {
280281
if (postprocessMaterial) {
281282
glBindFramebuffer(GL_FRAMEBUFFER, 0);
282283
postprocessMaterial->setup();
284+
285+
for (auto entity : world->getEntities()) {
286+
if (auto* effects = entity->getComponent<our::PostProcessEffectsComponent>()) {
287+
for (auto& [name, value] : effects->uniforms) {
288+
postprocessMaterial->shader->set(name, value);
289+
}
290+
break; // handles gameplay driven postprocess effects, other ones (like bloom) should be handled
291+
// separately outside this loop
292+
}
293+
}
294+
283295
glBindVertexArray(postProcessVertexArray);
284296
glDrawArrays(GL_TRIANGLES, 0, 3);
285297
}

src/common/systems/free-camera-controller.hpp

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ namespace our {
4545
// Get the entity that we found via getOwner of camera (we could use controller->getOwner())
4646
Entity* entity = camera->getOwner();
4747

48-
// We get a reference to the entity's position and rotation
49-
glm::vec3& position = entity->localTransform.position;
48+
// We get a reference to the entity's rotation
5049
glm::vec3& rotation = entity->localTransform.rotation;
5150

5251
// While the play state is active, the mouse stays locked
@@ -69,31 +68,6 @@ namespace our {
6968
fov = glm::clamp(fov, glm::pi<float>() * 0.01f,
7069
glm::pi<float>() * 0.99f); // We keep the fov in the range 0.01*PI to 0.99*PI
7170
camera->fovY = fov;
72-
73-
// We get the camera model matrix (relative to its parent) to compute the front and right directions
74-
glm::mat4 matrix = entity->localTransform.toMat4();
75-
76-
glm::vec3 front = glm::vec3(matrix * glm::vec4(0, 0, -1, 0));
77-
glm::vec3 right = glm::vec3(matrix * glm::vec4(1, 0, 0, 0));
78-
79-
glm::vec3 current_sensitivity = controller->positionSensitivity;
80-
// If the LEFT SHIFT key is pressed, we multiply the position sensitivity by the speed up factor
81-
if (app->getKeyboard().isPressed(GLFW_KEY_LEFT_SHIFT)) current_sensitivity *= controller->speedupFactor;
82-
83-
// We change the camera position based on the keys WASD
84-
glm::vec3 frontXZ = glm::normalize(glm::vec3(front.x, 0, front.z));
85-
glm::vec3 rightXZ = glm::normalize(glm::vec3(right.x, 0, right.z));
86-
87-
// S & W moves the player back and forth along the ground plane
88-
if (app->getKeyboard().isPressed(GLFW_KEY_W)) position += frontXZ * (deltaTime * current_sensitivity.z);
89-
if (app->getKeyboard().isPressed(GLFW_KEY_S)) position -= frontXZ * (deltaTime * current_sensitivity.z);
90-
// A & D moves the player left or right along the ground plane
91-
if (app->getKeyboard().isPressed(GLFW_KEY_D)) position += rightXZ * (deltaTime * current_sensitivity.x);
92-
if (app->getKeyboard().isPressed(GLFW_KEY_A)) position -= rightXZ * (deltaTime * current_sensitivity.x);
93-
94-
// stop the player from going below the ground plane
95-
float minY = controller->groundLevel + controller->playerHeight;
96-
if (position.y < minY) position.y = minY;
9771
}
9872

9973
// When the state exits, it should call this function to ensure the mouse is unlocked
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include "player-movement.hpp"
2+
3+
namespace gameplay {
4+
5+
void PlayerMovementComponent::deserialize(const nlohmann::json& data) {
6+
if (!data.is_object()) return;
7+
8+
walkSpeed = data.value("walkSpeed", walkSpeed);
9+
groundLevel = data.value("groundLevel", groundLevel);
10+
playerHeight = data.value("playerHeight", playerHeight);
11+
12+
sprintMultiplier = data.value("sprintMultiplier", sprintMultiplier);
13+
14+
crouchSpeed = data.value("crouchSpeed", crouchSpeed);
15+
crouchHeight = data.value("crouchHeight", crouchHeight);
16+
17+
slideSpeedMultiplier = data.value("slideSpeedMultiplier", slideSpeedMultiplier);
18+
slideDuration = data.value("slideDuration", slideDuration);
19+
slideCooldown = data.value("slideCooldown", slideCooldown);
20+
21+
dashDistance = data.value("dashDistance", dashDistance);
22+
dashCooldown = data.value("dashCooldown", dashCooldown);
23+
24+
jumpForce = data.value("jumpForce", jumpForce);
25+
gravity = data.value("gravity", gravity);
26+
}
27+
28+
} // namespace gameplay
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#pragma once
2+
3+
#include <ecs/component.hpp>
4+
#include <glm/glm.hpp>
5+
6+
namespace gameplay {
7+
8+
class PlayerMovementComponent : public our::Component {
9+
public:
10+
float walkSpeed = 5.0f;
11+
float groundLevel = 0.0f;
12+
float playerHeight = 1.7f;
13+
14+
float sprintMultiplier = 2.0f;
15+
16+
float crouchSpeed = 3.0f;
17+
float crouchHeight = 1.0f;
18+
19+
float slideSpeedMultiplier = 1.5f;
20+
float slideDuration = 1.0f;
21+
float slideCooldown = 0.3f;
22+
23+
float dashDistance = 5.0f;
24+
float dashCooldown = 1.5f;
25+
26+
float jumpForce = 8.0f;
27+
float gravity = 20.0f; // decrease for floatiness, can be a powerup easily
28+
29+
glm::vec3 velocity = {0, 0, 0};
30+
bool isSprinting = false;
31+
bool isCrouching = false;
32+
bool isSliding = false;
33+
float slideTimer = 0.0f;
34+
float slideCooldownTimer = 0.0f;
35+
float dashCooldownTimer = 0.0f;
36+
bool dashTriggeredThisFrame = false;
37+
float verticalVelocity = 0.0f;
38+
bool isGrounded = true;
39+
40+
static std::string getID() {
41+
return "PlayerMovement";
42+
}
43+
44+
void deserialize(const nlohmann::json& data) override;
45+
};
46+
47+
} // namespace gameplay

0 commit comments

Comments
 (0)