#ifndef LIGHTKEEPER_FIRSTPERSONCONTROLLER_H #define LIGHTKEEPER_FIRSTPERSONCONTROLLER_H #include #include #include class Rigidbody; class CapsuleCollider; // Dynamic capsule character. Velocity is driven directly (no forces) so movement stays responsive: // acceleration towards the wished velocity, own gravity, coyote time and jump buffering. class FirstPersonController final : public Component { public: explicit FirstPersonController(GameObject& parent); std::string GetTypeName() const override { return "FirstPersonController"; } void Start() override; void Update(float dt) override; void FixedUpdate(float fixedDt) override; void ImGuiInspector() override; nlohmann::json Serialize() const override; void Deserialize(const nlohmann::json& data) override; [[nodiscard]] float GetYaw() const { return m_Yaw; } void SetYaw(float yawRadians) { m_Yaw = yawRadians; } [[nodiscard]] float GetPitch() const { return m_Pitch; } [[nodiscard]] float GetEyeHeight() const { return m_EyeHeight; } // Eye position interpolated between the last two physics steps, so the camera moves smoothly at any framerate [[nodiscard]] glm::vec3 GetEyePosition() const; void SetMovementSpeed(float speed) { m_WalkSpeed = speed; } [[nodiscard]] float GetMovementSpeed() const { return m_WalkSpeed; } void SetMouseSensitivity(float sens) { m_MouseSensitivity = sens; } [[nodiscard]] float GetMouseSensitivity() const { return m_MouseSensitivity; } [[nodiscard]] bool IsGrounded() const { return m_Grounded; } [[nodiscard]] bool IsMouseCaptured() const { return InputManager::GetInstance().IsMouseCaptured(); } void SetMouseCaptured(bool captured); private: [[nodiscard]] bool CheckGrounded() const; [[nodiscard]] glm::vec3 GetWishDirection() const; Rigidbody* m_Rigidbody{nullptr}; CapsuleCollider* m_Capsule{nullptr}; float m_Yaw{0.0f}; float m_Pitch{0.0f}; float m_MouseSensitivity{0.002f}; float m_EyeHeight{0.7f}; // above the capsule center float m_WalkSpeed{5.0f}; float m_SprintSpeed{8.5f}; float m_GroundAcceleration{60.0f}; float m_AirAcceleration{15.0f}; float m_JumpHeight{1.3f}; float m_Gravity{22.0f}; float m_FallGravityMultiplier{1.6f}; float m_CoyoteTime{0.1f}; float m_JumpBufferTime{0.12f}; bool m_Grounded{false}; bool m_JumpHeld{false}; float m_CoyoteTimer{0.0f}; float m_JumpBufferTimer{0.0f}; glm::vec3 m_PreviousPosition{0.0f}; bool m_HasPreviousPosition{false}; }; #endif