feat: add firstpersoncontroller

This commit is contained in:
2026-09-05 01:11:44 +02:00
parent c9fb6e991a
commit e8a56405df
11 changed files with 251 additions and 20 deletions
+9 -5
View File
@@ -30,8 +30,8 @@ public:
int MouseX() const { return m_mouseX; }
int MouseY() const { return m_mouseY; }
int MouseDeltaX() const { return m_mouseDX; }
int MouseDeltaY() const { return m_mouseDY; }
int MouseDeltaX() const { return m_mouseRelDX; }
int MouseDeltaY() const { return m_mouseRelDY; }
int WheelX() const { return m_wheelX; }
int WheelY() const { return m_wheelY; }
@@ -81,6 +81,9 @@ public:
void SetAxisDeadzone(int deadzone) { m_axisDeadzone = deadzone; } // 0..32767
void SetMouseCaptured(bool captured);
[[nodiscard]] bool IsMouseCaptured() const { return m_MouseCaptured; }
private:
// Key states
std::unordered_set<SDL_Scancode> m_keysDown;
@@ -92,10 +95,9 @@ private:
std::unordered_set<Uint8> m_mousePressed;
std::unordered_set<Uint8> m_mouseReleased;
// Mouse position + delta
// Mouse position + relative delta (accumulated from SDL xrel/yrel)
int m_mouseX = 0, m_mouseY = 0;
int m_prevMouseX = 0, m_prevMouseY = 0;
int m_mouseDX = 0, m_mouseDY = 0;
int m_mouseRelDX = 0, m_mouseRelDY = 0;
int m_wheelX = 0, m_wheelY = 0;
@@ -125,6 +127,8 @@ private:
int m_axisDeadzone = 8000; // typical deadzone
bool m_MouseCaptured = false;
private:
bool QueryBinding(const Binding& b, ButtonState state) const;
+8 -8
View File
@@ -131,6 +131,12 @@ void App::run()
imguiPass.handleEvent(event);
const bool mouseEvent =
event.type == SDL_MOUSEBUTTONDOWN ||
event.type == SDL_MOUSEBUTTONUP ||
event.type == SDL_MOUSEMOTION ||
event.type == SDL_MOUSEWHEEL;
if (event.type == SDL_QUIT)
{
isRunning = false;
@@ -149,19 +155,13 @@ void App::run()
}
}
const bool mouseEvent =
event.type == SDL_MOUSEBUTTONDOWN ||
event.type == SDL_MOUSEBUTTONUP ||
event.type == SDL_MOUSEMOTION ||
event.type == SDL_MOUSEWHEEL;
const bool keyboardEvent =
event.type == SDL_KEYDOWN ||
event.type == SDL_KEYUP ||
event.type == SDL_TEXTINPUT;
const bool capturedByImgui =
(mouseEvent && imguiPass.wantsMouse()) ||
(mouseEvent && !InputManager::GetInstance().IsMouseCaptured() && imguiPass.wantsMouse()) ||
(keyboardEvent && imguiPass.wantsKeyboard());
if (!capturedByImgui)
@@ -176,7 +176,7 @@ void App::run()
}
}
if (!isRunning) break;
if (!isRunning) break;
// Consume SDL events before updating the base camera so held and
// newly pressed inputs are applied in the same frame.
+1 -1
View File
@@ -114,7 +114,7 @@ void Camera::SetRotation(const glm::vec2& yawPitchRadians) {
SetRotation(yawPitchRadians.x, yawPitchRadians.y);
}
void Camera::SetTarget(const glm::vec3& target) {
void Camera::SetTarget(const glm::vec3&) {
}
void Camera::ClearTarget() {
@@ -124,6 +124,11 @@ void ImguiPass::beginFrame() {
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame();
if (SDL_GetRelativeMouseMode() == SDL_TRUE) {
ImGui::GetIO().MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
}
ImGui::NewFrame();
frameBegun = true;
+13 -5
View File
@@ -46,11 +46,11 @@ void InputManager::BeginFrame() {
m_textInput.clear();
// Update mouse delta based on last known position
m_mouseDX = m_mouseX - m_prevMouseX;
m_mouseDY = m_mouseY - m_prevMouseY;
m_prevMouseX = m_mouseX;
m_prevMouseY = m_mouseY;
// Relative mouse accumulators are filled during SDL event processing
// and consumed by game code each frame. Reset them here (before events
// are processed) so this frame accumulates fresh deltas.
m_mouseRelDX = 0;
m_mouseRelDY = 0;
// Clear controller "edge" sets + snapshot axes
for (auto& [id, pad]: m_pads) {
@@ -60,6 +60,12 @@ void InputManager::BeginFrame() {
}
}
void InputManager::SetMouseCaptured(bool captured) {
if (captured == m_MouseCaptured) return;
m_MouseCaptured = captured;
SDL_SetRelativeMouseMode(captured ? SDL_TRUE : SDL_FALSE);
}
void InputManager::AddController(int deviceIndex) {
if (!SDL_IsGameController(deviceIndex)) return;
@@ -134,6 +140,8 @@ bool InputManager::ProcessEvent(const SDL_Event& e) {
case SDL_MOUSEMOTION: {
m_mouseX = e.motion.x;
m_mouseY = e.motion.y;
m_mouseRelDX += e.motion.xrel;
m_mouseRelDY += e.motion.yrel;
}
break;