#ifndef LIGHTKEEPER_FIRSTPERSONCONTROLLER_H #define LIGHTKEEPER_FIRSTPERSONCONTROLLER_H #include #include #include #include class Rigidbody; class CapsuleCollider; class Interactable; 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 Reflect(FieldVisitor& v) override; void ImGuiInspector() 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; } void SetPitch(float pitchRadians) { m_Pitch = pitchRadians; } [[nodiscard]] float GetEyeHeight() const { return m_EyeHeight; } [[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; } void Teleport(const glm::vec3& worldPosition); [[nodiscard]] Interactable* GetFocusedInteractable() const { return m_FocusedInteractable; } [[nodiscard]] glm::vec3 GetLookDirection() const; [[nodiscard]] bool IsPossessed() const { return m_Possessed; } void SetPossessed(bool possessed); private: struct GroundContact { glm::vec3 normal; glm::vec3 velocity; }; [[nodiscard]] std::optional FindGround() const; [[nodiscard]] glm::vec3 GetWishDirection() const; [[nodiscard]] Interactable* FindFocusedInteractable() 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}; float m_InteractDistance{3.0f}; float m_MaxSlopeAngle{glm::radians(50.0f)}; float m_GroundStickSpeed{2.0f}; Interactable* m_FocusedInteractable{nullptr}; bool m_Possessed{false}; bool m_Grounded{false}; glm::vec3 m_GroundNormal{0.0f, 1.0f, 0.0f}; 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