diff options
Diffstat (limited to 'src/crepe/system')
-rw-r--r-- | src/crepe/system/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/crepe/system/InputSystem.cpp | 147 | ||||
-rw-r--r-- | src/crepe/system/InputSystem.h | 76 |
3 files changed, 225 insertions, 0 deletions
diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt index d658b25..95f6e33 100644 --- a/src/crepe/system/CMakeLists.txt +++ b/src/crepe/system/CMakeLists.txt @@ -6,6 +6,7 @@ target_sources(crepe PUBLIC CollisionSystem.cpp RenderSystem.cpp AnimatorSystem.cpp + InputSystem.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -15,4 +16,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES CollisionSystem.h RenderSystem.h AnimatorSystem.h + InputSystem.h ) diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp new file mode 100644 index 0000000..beeef87 --- /dev/null +++ b/src/crepe/system/InputSystem.cpp @@ -0,0 +1,147 @@ +#include "ComponentManager.h" +#include "api/Button.h" +#include "api/EventManager.h" + +#include "InputSystem.h" + +using namespace crepe; + +void InputSystem::update() { + EventManager & event_mgr = EventManager::get_instance(); + std::vector<SDLContext::EventData> event_list = SDLContext::get_instance().get_events(); + + for (const SDLContext::EventData & event : event_list) { + switch (event.event_type) { + case SDLContext::EventType::KEYDOWN: + event_mgr.queue_event<KeyPressEvent>(KeyPressEvent{ + .repeat = event.key_repeat, + .key = event.key, + }); + break; + case SDLContext::EventType::KEYUP: + event_mgr.queue_event<KeyReleaseEvent>(KeyReleaseEvent{ + .key = event.key, + }); + break; + case SDLContext::EventType::MOUSEDOWN: + event_mgr.queue_event<MousePressEvent>(MousePressEvent{ + .mouse_x = event.mouse_position.first, + .mouse_y = event.mouse_position.second, + .button = event.mouse_button, + }); + last_mouse_down_position = event.mouse_position; + last_mouse_button = event.mouse_button; + break; + case SDLContext::EventType::MOUSEUP: { + event_mgr.queue_event<MouseReleaseEvent>(MouseReleaseEvent{ + .mouse_x = event.mouse_position.first, + .mouse_y = event.mouse_position.second, + .button = event.mouse_button, + }); + + int delta_x = event.mouse_position.first - last_mouse_down_position.first; + int delta_y = event.mouse_position.second - last_mouse_down_position.second; + + if (last_mouse_button == event.mouse_button + && std::abs(delta_x) <= click_tolerance + && std::abs(delta_y) <= click_tolerance) { + event_mgr.queue_event<MouseClickEvent>(MouseClickEvent{ + .mouse_x = event.mouse_position.first, + .mouse_y = event.mouse_position.second, + .button = event.mouse_button, + }); + + handle_click(event); + } + } break; + case SDLContext::EventType::MOUSEMOVE: + event_mgr.queue_event<MouseMoveEvent>(MouseMoveEvent{ + .mouse_x = event.mouse_position.first, + .mouse_y = event.mouse_position.second, + .rel_x = event.rel_mouse_move.first, + .rel_y = event.rel_mouse_move.second, + }); + handle_move(event); + break; + case SDLContext::EventType::MOUSEWHEEL: + event_mgr.queue_event<MouseScrollEvent>(MouseScrollEvent{ + .scroll_x = event.wheel_delta, + .scroll_y = 0, + .direction = event.wheel_delta, + }); + break; + case SDLContext::EventType::SHUTDOWN: + event_mgr.queue_event<ShutDownEvent>(ShutDownEvent{}); + break; + default: + break; + } + } +} + +void InputSystem::handle_move(const SDLContext::EventData & event_data) { + ComponentManager & mgr = this->component_manager; + + RefVector<Button> buttons = mgr.get_components_by_type<Button>(); + + for (Button & button : buttons) { + RefVector<Transform> transform_vec + = mgr.get_components_by_id<Transform>(button.game_object_id); + OptionalRef<Transform> transform(transform_vec.front().get()); + if (!transform) continue; + + bool was_hovering = button.hover; // Store previous hover state + + // Check if the mouse is inside the button + if (button.active && is_mouse_inside_button(event_data, button, transform)) { + button.hover = true; + + // Trigger the on_enter callback if the hover state just changed to true + if (!was_hovering && button.on_enter) { + button.on_enter(); + } + } else { + button.hover = false; + + // Trigger the on_exit callback if the hover state just changed to false + if (was_hovering && button.on_exit) { + button.on_exit(); + } + } + } +} + +void InputSystem::handle_click(const SDLContext::EventData & event_data) { + ComponentManager & mgr = this->component_manager; + + RefVector<Button> buttons = mgr.get_components_by_type<Button>(); + + for (Button & button : buttons) { + RefVector<Transform> transform_vec + = mgr.get_components_by_id<Transform>(button.game_object_id); + OptionalRef<Transform> transform(transform_vec.front().get()); + + if (button.active && is_mouse_inside_button(event_data, button, transform)) { + handle_button_press(button); + } + } +} + +bool InputSystem::is_mouse_inside_button(const SDLContext::EventData & event_data, + const Button & button, const Transform & transform) { + return event_data.mouse_position.first >= transform.position.x + && event_data.mouse_position.first <= transform.position.x + button.width + && event_data.mouse_position.second >= transform.position.y + && event_data.mouse_position.second <= transform.position.y + button.height; +} + +void InputSystem::handle_button_press(Button & button) { + if (button.is_toggle) { + if (!button.is_pressed && button.on_click) { + button.on_click(); + } + button.is_pressed = !button.is_pressed; + } else if (button.on_click) { + button.on_click(); + } +} diff --git a/src/crepe/system/InputSystem.h b/src/crepe/system/InputSystem.h new file mode 100644 index 0000000..c6ca114 --- /dev/null +++ b/src/crepe/system/InputSystem.h @@ -0,0 +1,76 @@ +#pragma once + +#include "facade/SDLContext.h" +#include "types.h" +#include "util/OptionalRef.h" + +#include "System.h" + +namespace crepe { + +class Button; + +class Transform; +/** + * \class InputSystem + * \brief Handles the processing of input events like mouse and keyboard interactions. + * + * This system processes events such as mouse clicks, mouse movement, and keyboard + * actions. It is responsible for detecting interactions with UI buttons and + * passing the corresponding events to the registered listeners. + */ +class InputSystem : public System { +public: + using System::System; + + /** + * \brief Updates the system, processing all input events. + * This method processes all events and triggers corresponding actions. + */ + void update() override; + +private: + //! Stores the last position of the mouse when the button was pressed. + std::pair<int, int> last_mouse_down_position{-1, -1}; + + //! Stores the last mouse button pressed. + MouseButton last_mouse_button = MouseButton::NONE; + + //! The tolerance in game units for detecting a mouse click. + const int click_tolerance = 5; + + /** + * \brief Handles the click event. + * \param eventData The event data containing information about the mouse click. + * + * This method processes the mouse click event and triggers the corresponding button action. + */ + void handle_click(const SDLContext::EventData & eventData); + + /** + * \brief Handles the mouse movement event. + * \param eventData The event data containing information about the mouse movement. + * + * This method processes the mouse movement event and updates the button hover state. + */ + void handle_move(const SDLContext::EventData & eventData); + /** + * \brief Checks if the mouse position is inside the bounds of the button. + * \param eventData The event data containing the mouse position. + * \param button The button to check. + * \param transform The transform component of the button. + * \return True if the mouse is inside the button, false otherwise. + */ + bool is_mouse_inside_button(const SDLContext::EventData & eventData, const Button & button, + const Transform & transform); + + /** + * \brief Handles the button press event, calling the on_click callback if necessary. + * \param button The button being pressed. + * + * This method triggers the on_click action for the button when it is pressed. + */ + void handle_button_press(Button & button); +}; + +} // namespace crepe |