Monad Engine da02fba2
> Undercity Codex_
Loading...
Searching...
No Matches
PlayerControllerComponent.cpp
Go to the documentation of this file.
1#include "scene/components/PlayerControllerComponent.h"
2
3#include <algorithm>
4#include <cmath>
5
6#include "Constants.h"
7#include "Engine.h"
8#include "GLFW/glfw3.h"
9#include "Types.h"
10#include "editor/Editor.h"
11#include "input/InputManager.h"
12
13namespace mnd
14{
15
16namespace
17{
18constexpr f32 kMinHorizontalSpeed = 1e-4F;
19
20vec3 FlattenY(const vec3 &v)
21{
22 return vec3(v.x, 0.0F, v.z);
23}
24} // namespace
25
27{
28 m_kinematicController = std::make_unique<KinematicCharacterController>(
30}
31
32void PlayerControllerComponent::ApplyFriction(f32 deltaTime)
33{
34 f32 speed = glm::length(FlattenY(m_velocity));
35 if (speed < kMinHorizontalSpeed)
36 {
37 m_velocity.x = 0.0F;
38 m_velocity.z = 0.0F;
39 return;
40 }
41 f32 control = (speed < kQuakeStopSpeed) ? kQuakeStopSpeed : speed;
42 f32 drop = control * m_friction * deltaTime;
43 f32 newSpeed = std::max(0.0F, speed - drop);
44 f32 scale = newSpeed / speed;
45 m_velocity.x *= scale;
46 m_velocity.z *= scale;
47}
48
49void PlayerControllerComponent::Accelerate(const vec3 &wishDir, f32 wishSpeed, f32 accel, f32 deltaTime)
50{
51 f32 currentSpeed = glm::dot(m_velocity, wishDir);
52 f32 addSpeed = wishSpeed - currentSpeed;
53 if (addSpeed <= 0.0F)
54 {
55 return;
56 }
57 f32 accelSpeed = accel * deltaTime * wishSpeed;
58 if (accelSpeed > addSpeed)
59 {
60 accelSpeed = addSpeed;
61 }
62 m_velocity += accelSpeed * wishDir;
63}
64
66{
67 auto &inputManager = Engine::GetInstance().GetInputManager();
68 const bool editorOpen = Engine::GetInstance().GetEditor().IsVisible();
69
70 auto rotation = m_owner->GetRotation();
71
72 if (!editorOpen && inputManager.IsMousePositionChanged())
73 {
74 const auto &oldPos = inputManager.GetMousePositionOld();
75 const auto &currentPos = inputManager.GetMousePositionCurrent();
76
77 f32 deltaX = currentPos.x - oldPos.x;
78 f32 deltaY = currentPos.y - oldPos.y;
79
80 f32 yDeltaAngle = -deltaX * m_sensitivity * deltaTime;
81 m_yRot += yDeltaAngle;
82 glm::quat yRot = glm::angleAxis(glm::radians(m_yRot), glm::vec3(0, 1, 0));
83
84 f32 xDeltaAngle = -deltaY * m_sensitivity * deltaTime;
85 m_xRot += xDeltaAngle;
86 m_xRot = std::clamp(m_xRot, -kPitchLimitDegrees, kPitchLimitDegrees);
87 glm::quat xRot = glm::angleAxis(glm::radians(m_xRot), glm::vec3(1, 0, 0));
88
89 rotation = glm::normalize(yRot * xRot);
90 m_owner->SetRotation(rotation);
91 }
92
93 if (editorOpen)
94 {
95 m_velocity = vec3(0.0F);
96 m_kinematicController->Walk(vec3(0.0F));
97 m_owner->SetPosition(m_kinematicController->GetPosition());
98 return;
99 }
100
101 // Build horizontal-plane basis from yaw only — pitch shouldn't tilt motion.
102 vec3 front = glm::normalize(FlattenY(rotation * vec3(0.0F, 0.0F, -1.0F)));
103 vec3 right = glm::normalize(FlattenY(rotation * vec3(1.0F, 0.0F, 0.0F)));
104
105 vec3 wish(0.0F);
106 if (inputManager.IsKeyPressed(Key::A))
107 {
108 wish -= right;
109 } else if (inputManager.IsKeyPressed(Key::D))
110 {
111 wish += right;
112 }
113 if (inputManager.IsKeyPressed(Key::W))
114 {
115 wish += front;
116 } else if (inputManager.IsKeyPressed(Key::S))
117 {
118 wish -= front;
119 }
120
121 vec3 wishDir(0.0F);
122 f32 wishMag = glm::length(wish);
123 if (wishMag > kMinHorizontalSpeed)
124 {
125 wishDir = wish / wishMag;
126 }
127
128 const bool onGround = m_kinematicController->OnGround();
129 const bool jumpPressed = inputManager.IsKeyPressed(Key::Space);
130
131 if (onGround)
132 {
133 ApplyFriction(deltaTime);
134 Accelerate(wishDir, m_moveSpeed, m_groundAccel, deltaTime);
135 } else
136 {
137 // Air control: cap wishspeed so high-speed strafe-jumping stays possible
138 // while still letting the player nudge direction in the air.
139 f32 airWishSpeed = std::min(m_moveSpeed, m_airCap);
140 Accelerate(wishDir, airWishSpeed, m_airAccel, deltaTime);
141 }
142
143 // Horizontal motion: pass per-frame displacement to the kinematic controller.
144 m_kinematicController->Walk(vec3(m_velocity.x * deltaTime, 0.0F, m_velocity.z * deltaTime));
145
146 // Bunny-hop: with auto-hop, jump fires every frame Space is held while on
147 // ground (so you bhop just by holding it). Without it, you have to retap.
148 if (onGround && jumpPressed && (m_autoHop || !m_jumpHeldLast))
149 {
150 m_kinematicController->Jump(vec3(0.0F, m_moveSpeed * m_jumpSpeed, 0.0F));
151 }
152 m_jumpHeldLast = jumpPressed;
153
154 m_owner->SetPosition(m_kinematicController->GetPosition());
155}
156
158{
159 if (m_kinematicController)
160 {
161 return m_kinematicController->OnGround();
162 }
163 return false;
164}
165
167{
168 m_moveSpeed = speed;
169}
170
172{
173 return m_moveSpeed;
174}
175
176} // namespace mnd
Engine-wide compile-time tunables and ANSI colour codes.
constexpr mnd::f32 kQuakeStopSpeed
sv_stopspeed (100 ups).
Definition Constants.h:93
constexpr mnd::f32 kDefaultCapsuleRadius
Definition Constants.h:68
constexpr mnd::f32 kDefaultCapsuleHeight
Definition Constants.h:69
constexpr mnd::f32 kPitchLimitDegrees
Definition Constants.h:73
In-game ImGui overlay: hierarchy, inspector, console, stats.
Engine-wide primitive type aliases and GLM math imports.
GameObject * m_owner
Definition Component.h:57
bool IsVisible() const
Editor overlay currently shown?
Definition Editor.h:57
InputManager & GetInputManager()
Returns the InputManager that tracks keyboard and mouse state.
Definition Engine.cpp:413
Editor & GetEditor()
ImGui-based editor overlay.
Definition Engine.h:149
static Engine & GetInstance()
Returns the single Engine instance (created on first call).
Definition Engine.cpp:59
vec3 GetWorldPosition() const
Extract the world-space position from GetWorldTransform().
void SetPosition(const vec3 &pos)
void SetRotation(const quat &rot)
const quat & GetRotation() const
glm::vec3 vec3
3-component float vector (e.g. world position, RGB colour, normals).
Definition Types.h:51
float f32
32-bit IEEE float — the standard GL scalar type.
Definition Types.h:40