diff options
-rw-r--r-- | src/crepe/api/Button.cpp | 0 | ||||
-rw-r--r-- | src/crepe/api/Button.h | 17 | ||||
-rw-r--r-- | src/crepe/api/Event.h | 10 | ||||
-rw-r--r-- | src/crepe/api/LoopManager.cpp | 4 | ||||
-rw-r--r-- | src/crepe/api/UiObject.h | 14 | ||||
-rw-r--r-- | src/crepe/facade/SDLContext.cpp | 80 | ||||
-rw-r--r-- | src/crepe/facade/SDLContext.h | 40 | ||||
-rw-r--r-- | src/crepe/system/InputSystem.cpp | 107 | ||||
-rw-r--r-- | src/crepe/system/InputSystem.h | 23 | ||||
-rw-r--r-- | src/example/gameloop.cpp | 33 | ||||
-rw-r--r-- | src/test/inputTest.cpp | 53 | ||||
-rw-r--r-- | src/test/loopTimerTest.cpp | 32 |
12 files changed, 404 insertions, 9 deletions
diff --git a/src/crepe/api/Button.cpp b/src/crepe/api/Button.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/crepe/api/Button.cpp diff --git a/src/crepe/api/Button.h b/src/crepe/api/Button.h new file mode 100644 index 0000000..5035729 --- /dev/null +++ b/src/crepe/api/Button.h @@ -0,0 +1,17 @@ +#include <functional> + +#include "Component.h" +#include "api/EventHandler.h" +#include "api/UiObject.h" +namespace crepe { +class Button : public UiObject{ +public: + ~Button(){}; + bool interactable = true; + bool is_toggle = false; + bool is_pressed = false; + std::function<void()> on_click; +public: +virtual int get_instances_max() const { return 1; } +}; +} diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h index b267e3e..bac8701 100644 --- a/src/crepe/api/Event.h +++ b/src/crepe/api/Event.h @@ -88,6 +88,10 @@ public: //! Y-coordinate of the mouse position at the time of the event. int mouse_y = 0; + // Relative movement in x + int rel_x; + // Relative movement in y + int rel_y; }; /** @@ -107,6 +111,8 @@ public: /** * \brief Event triggered to indicate the application is shutting down. */ -class ShutDownEvent : public Event {}; +class ShutDownEvent : public Event { +public: +}; -} // namespace crepe +} diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 7edf4d1..9599943 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -6,6 +6,7 @@ #include "../system/PhysicsSystem.h" #include "../system/RenderSystem.h" #include "../system/ScriptSystem.h" +#include "../system/InputSystem.h" #include "LoopManager.h" #include "LoopTimer.h" @@ -20,10 +21,11 @@ LoopManager::LoopManager() { this->load_system<PhysicsSystem>(); this->load_system<RenderSystem>(); this->load_system<ScriptSystem>(); + this->load_system<InputSystem>(); } void LoopManager::process_input() { - SDLContext::get_instance().handle_events(this->game_running); + this->get_system<InputSystem>().update(); } void LoopManager::start() { diff --git a/src/crepe/api/UiObject.h b/src/crepe/api/UiObject.h new file mode 100644 index 0000000..f57f7ef --- /dev/null +++ b/src/crepe/api/UiObject.h @@ -0,0 +1,14 @@ +#include <functional> + +#include "Component.h" +#include "api/EventHandler.h" +namespace crepe { +class UiObject : public Component{ +public: + ~UiObject(){}; + int width = 0; + int height = 0; +public: +virtual int get_instances_max() const { return 1; } +}; +} diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index b3298a7..ff7c9f0 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -11,14 +11,15 @@ #include <memory> #include <stdexcept> #include <string> +#include <array> #include "../api/Camera.h" #include "../api/Sprite.h" #include "../api/Texture.h" #include "../api/Transform.h" -#include "../api/Vector2.h" #include "../util/Log.h" + #include "SDLContext.h" using namespace crepe; @@ -72,6 +73,7 @@ SDLContext::~SDLContext() { IMG_Quit(); SDL_Quit(); } + void SDLContext::handle_events(bool & running) { //TODO: wouter i need events /* @@ -192,3 +194,79 @@ int SDLContext::get_height(const Texture & ctx) const { return h; } void SDLContext::delay(int ms) const { SDL_Delay(ms); } + +std::vector<SDLContext::EventData> SDLContext::get_events(){ + std::vector<SDLContext::EventData> event_list; + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + event_list.push_back(EventData{ + .event_type = SDLContext::Event::SHUTDOWN, + }); + break; + case SDL_KEYDOWN: + event_list.push_back(EventData{ + .event_type = SDLContext::Event::KEYDOWN, + .key = sdl_to_keycode(event.key.keysym.scancode), + .key_repeat = (event.key.repeat != 0), + }); + break; + case SDL_KEYUP: + event_list.push_back(EventData{ + .event_type = SDLContext::Event::KEYUP, + .key = sdl_to_keycode(event.key.keysym.scancode), + }); + break; + case SDL_MOUSEBUTTONDOWN: + { + int x,y; + SDL_GetMouseState(&x, &y); + event_list.push_back(EventData{ + .event_type = SDLContext::Event::MOUSEDOWN, + .mouse_button = sdl_to_mousebutton(event.button.button), + .mouse_position = {x,y}, + }); + } + break; + case SDL_MOUSEBUTTONUP: + { + int x,y; + SDL_GetMouseState(&x, &y); + event_list.push_back(EventData{ + .event_type = SDLContext::Event::MOUSEUP, + .mouse_button = sdl_to_mousebutton(event.button.button), + .mouse_position = {x,y}, + }); + } + break; + + case SDL_MOUSEMOTION: + { + int x,y; + SDL_GetMouseState(&x, &y); + event_list.push_back(EventData{ + .event_type = SDLContext::Event::MOUSEMOVE, + .mouse_position = {x,y}, + }); + } + break; + + case SDL_MOUSEWHEEL: + { + int x, y; + SDL_GetMouseState(&x, &y); + + event_list.push_back(EventData{ + .event_type = SDLContext::Event::MOUSEWHEEL, + .mouse_position = {event.motion.x,event.motion.y}, + .wheel_delta = event.wheel.y, + .rel_mouse_move {event.motion.yrel,event.motion.xrel}, + }); + } + break; + } + } + return event_list; +} + diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 20e30b3..5b6b093 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -1,5 +1,5 @@ #pragma once - +#include <SDL2/SDL.h> #include <SDL2/SDL_keycode.h> #include <SDL2/SDL_rect.h> #include <SDL2/SDL_render.h> @@ -10,7 +10,10 @@ #include <string> #include "../api/Sprite.h" +#include "../api/KeyCodes.h" #include "../api/Transform.h" +#include "../api/Vector2.h" +#include "../api/Event.h" #include "api/Camera.h" #include "types.h" @@ -19,8 +22,9 @@ namespace crepe { // TODO: SDL_Keycode is defined in a header not distributed with crepe, which means this // typedef is unusable when crepe is packaged. Wouter will fix this later. -typedef SDL_Keycode CREPE_KEYCODES; - +//typedef SDL_Keycode CREPE_KEYCODES; +class LoopManager; +class InputSystem; /** * \class SDLContext * \brief Facade for the SDL library @@ -31,6 +35,26 @@ typedef SDL_Keycode CREPE_KEYCODES; class SDLContext { public: + enum Event{ + NONE = 0, + MOUSEDOWN, + MOUSEUP, + MOUSEMOVE, + MOUSEWHEEL, + KEYUP, + KEYDOWN, + SHUTDOWN + + }; + struct EventData { + SDLContext::Event event_type = SDLContext::Event::NONE; + Keycode key = Keycode::NONE; + bool key_repeat = false; + MouseButton mouse_button = MouseButton::NONE; + std::pair<int,int> mouse_position = {-1,-1}; + int wheel_delta = -1; + std::pair<int,int> rel_mouse_move = {-1,-1}; + }; /** * \brief Gets the singleton instance of SDLContext. * \return Reference to the SDLContext instance. @@ -44,13 +68,18 @@ public: private: //! will only use handle_events - friend class LoopManager; + friend class InputSystem; /** * \brief Handles SDL events such as window close and input. * \param running Reference to a boolean flag that controls the main loop. */ void handle_events(bool & running); - + std::vector<SDLContext::EventData> get_events(); + + Keycode get_key(); + Keycode get_mouse(); + Keycode sdl_to_keycode(SDL_Keycode sdlKey); + MouseButton sdl_to_mousebutton(Uint8 sdl_button); private: //! Will only use get_ticks friend class AnimatorSystem; @@ -168,4 +197,5 @@ private: SDL_Rect viewport = {0, 0, 640, 480}; }; + } // namespace crepe diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp new file mode 100644 index 0000000..c61a80f --- /dev/null +++ b/src/crepe/system/InputSystem.cpp @@ -0,0 +1,107 @@ +#include "ComponentManager.h" +#include "../api/Button.h" +#include "../api/EventManager.h" +#include "../api/Transform.h" +#include "../facade/SDLContext.h" +#include "../api/Event.h" + +#include "system/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 (SDLContext::EventData event : event_list) { + switch (event.event_type) { + case SDLContext::Event::KEYDOWN: { + event_mgr.queue_event(KeyPressEvent{ + .key = event.key, + .repeat = event.key_repeat, + }); + break; + } + case SDLContext::Event::KEYUP: { + event_mgr.queue_event(KeyReleaseEvent{ + .key = event.key, + }); + break; + } + case SDLContext::Event::MOUSEDOWN: { + event_mgr.queue_event(MousePressEvent{ + .mouse_x = event.mouse_position.first, + .mouse_y = event.mouse_position.second, + .button = event.mouse_button, + }); + break; + } + case SDLContext::Event::MOUSEMOVE: { + event_mgr.queue_event(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, + }); + break; + } + case SDLContext::Event::MOUSEUP: { + event_mgr.queue_event(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{ + .mouse_x = event.mouse_position.first, + .mouse_y = event.mouse_position.second, + .button = event.mouse_button, + }); + } + break; + } + case SDLContext::Event::MOUSEWHEEL: { + event_mgr.queue_event(MouseScrollEvent{ + .scroll_x = event.mouse_position.first, + .scroll_y = event.mouse_position.second, + .direction = event.wheel_delta, + }); + break; + } + case SDLContext::Event::SHUTDOWN: { + event_mgr.queue_event(ShutDownEvent{}); + break; + } + default: + break; + } + } +} + +bool InputSystem::handle_click(const MouseClickEvent &event) { + ComponentManager &mgr = this->component_manager; + + std::vector<std::reference_wrapper<Button>> buttons = + mgr.get_components_by_type<Button>(); + + std::vector<std::reference_wrapper<Transform>> transforms = + mgr.get_components_by_type<Transform>(); + for (Button &button : buttons) { + for(Transform& transform : transforms){ + if(button.game_object_id != transform.game_object_id){continue;} + if (!button.interactable) {break;} + if (event.mouse_x >= transform.position.x && event.mouse_x <= transform.position.x + button.width && + event.mouse_y >= transform.position.y && event.mouse_y <= transform.position.y + button.height) { + button.on_click(); + } + } + } + return false; +} + diff --git a/src/crepe/system/InputSystem.h b/src/crepe/system/InputSystem.h new file mode 100644 index 0000000..231aa45 --- /dev/null +++ b/src/crepe/system/InputSystem.h @@ -0,0 +1,23 @@ +#pragma once + +#include "System.h" +#include "../api/Event.h" +namespace crepe { + +class InputSystem : public System { +public: + using System::System; + void update() override; + void process_events(); + +private: + std::pair<int, int> last_mouse_down_position{-1, -1}; + MouseButton last_mouse_button = MouseButton::NONE; + const int click_tolerance = 5; + bool handle_click(const MouseClickEvent &event); + bool handle_move(const MouseMoveEvent &event); + bool handle_key_press(const KeyPressEvent &event); + bool handle_key_release(const KeyReleaseEvent &event); +}; + +} // namespace crepe diff --git a/src/example/gameloop.cpp b/src/example/gameloop.cpp index a676f20..d45b3ce 100644 --- a/src/example/gameloop.cpp +++ b/src/example/gameloop.cpp @@ -1,7 +1,40 @@ +#include <iostream> #include "crepe/api/LoopManager.h" +#include <crepe/api/EventManager.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/IKeyListener.h> +#include <crepe/api/IMouseListener.h> using namespace crepe; +class TestKeyListener : public IKeyListener { +public: + bool on_key_pressed(const KeyPressEvent & event) override { + std::cout << "TestKeyListener: Key Pressed - Code: " << static_cast<int>(event.key) + << std::endl; + if(event.key == Keycode::ESCAPE){ + + } + return false; + } + bool on_key_released(const KeyReleaseEvent & event) override { + std::cout << "TestKeyListener: Key Released - Code: " << static_cast<int>(event.key) + << std::endl; + return false; + } +}; +bool on_key_pressed(const KeyPressEvent & event){ + std::cout << "TestKeyListener: Key Pressed - Code: " << static_cast<int>(event.key) + << std::endl; + if(event.key == Keycode::ESCAPE){ + return true; + } + return false; + } int main() { LoopManager gameloop; + TestKeyListener key_listener; + EventManager::get_instance().subscribe<KeyPressEvent>(on_key_pressed); gameloop.start(); + + return 1; } diff --git a/src/test/inputTest.cpp b/src/test/inputTest.cpp new file mode 100644 index 0000000..0f02410 --- /dev/null +++ b/src/test/inputTest.cpp @@ -0,0 +1,53 @@ +#include <SDL2/SDL.h> +#include <SDL2/SDL_keycode.h> +#include "system/InputSystem.h" +#include "api/EventManager.h" +#include "api/KeyCodes.h" +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +using namespace std; +using namespace std::chrono_literals; +using namespace crepe; + +class InputTest : public ::testing::Test { +public: +InputSystem input_system; +EventManager& event_manager = EventManager::get_instance(); +protected: + void SetUp() override { + } + + void TearDown() override { + + } +void simulate_mouse_click(int mouse_x, int mouse_y, Uint8 mouse_button) { + SDL_Event event; + + // Simulate Mouse Button Down event + SDL_zero(event); + event.type = SDL_MOUSEBUTTONDOWN; + event.button.x = mouse_x; + event.button.y = mouse_y; + event.button.button = mouse_button; + SDL_PushEvent(&event); + SDL_zero(event); + event.type = SDL_MOUSEBUTTONUP; + event.button.x = mouse_x; + event.button.y = mouse_y; + event.button.button = mouse_button; + SDL_PushEvent(&event); +} + +}; + +TEST_F(InputTest, KeyDown) { + + SDL_Event event; + SDL_zero(event); + event.type = SDL_MOUSEBUTTONDOWN; + event.button.x = 10; + event.button.y = 10; + event.button.button = mouse_bu; + SDL_PushEvent(&event); // Push event into the SDL event queue +} diff --git a/src/test/loopTimerTest.cpp b/src/test/loopTimerTest.cpp new file mode 100644 index 0000000..a3b1646 --- /dev/null +++ b/src/test/loopTimerTest.cpp @@ -0,0 +1,32 @@ +#define private public +#define protected public +#include "api/LoopManager.h" +#include "api/LoopTimer.h" +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +using namespace std; +using namespace std::chrono_literals; +using namespace crepe; + +class LoopTimerTest : public ::testing::Test { +public: +LoopTimer loop_timer = LoopTimer::get_instance(); +protected: + void SetUp() override { + loop_timer.start(); + } + + void TearDown() override { + + } +}; +TEST_F(LoopTimerTest, TestDeltaTime) { + auto start_time = std::chrono::steady_clock::now(); + + loop_timer.update(); + double delta_time = loop_timer.get_delta_time(); + + auto elapsed_time = std::chrono::steady_clock::now() - start_time; + EXPECT_LE(delta_time, std::chrono::duration<double>(elapsed_time).count()); +} |