diff options
Diffstat (limited to 'mwe/events')
36 files changed, 1766 insertions, 0 deletions
diff --git a/mwe/events/CMakeLists.txt b/mwe/events/CMakeLists.txt new file mode 100644 index 0000000..12e45a7 --- /dev/null +++ b/mwe/events/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.5) +project(gameloop) + +# Set the C++ standard (optional, but good practice) +set(CMAKE_C_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) +set(CMAKE_BUILD_TYPE Debug) + +# Find the SDL2 package +find_package(SDL2 REQUIRED) +# Find the SDL2_ttf package +find_package(SDL2_ttf REQUIRED) + +add_executable(gameloop + src/window.cpp + src/main.cpp + src/eventManager.cpp + src/event.cpp + src/loopManager.cpp + src/timer.cpp + src/keyCodes.cpp + src/eventHandler.cpp + src/iMouseListener.cpp + src/iKeyListener.cpp + src/mouseListenerTest.cpp + src/keyListenerTest.cpp + src/inputSystem.cpp + src/uiRenderer.cpp + src/uiObject.cpp +) + +target_link_libraries(gameloop ${SDL2_LIBRARIES} SDL2_ttf::SDL2_ttf) + +# Include SDL2 header files and project headers +target_include_directories(gameloop PRIVATE ${SDL2_INCLUDE_DIRS}) +target_include_directories(gameloop PRIVATE ${CMAKE_SOURCE_DIR}/include) + +# Copy font files to the build directory +file(COPY ${PROJECT_SOURCE_DIR}/font DESTINATION ${CMAKE_BINARY_DIR}) diff --git a/mwe/events/imgs/demo.bmp b/mwe/events/imgs/demo.bmp Binary files differnew file mode 100644 index 0000000..65354fe --- /dev/null +++ b/mwe/events/imgs/demo.bmp diff --git a/mwe/events/imgs/demo.jpg b/mwe/events/imgs/demo.jpg Binary files differnew file mode 100644 index 0000000..f534e1b --- /dev/null +++ b/mwe/events/imgs/demo.jpg diff --git a/mwe/events/include/customTypes.h b/mwe/events/include/customTypes.h new file mode 100644 index 0000000..5a7851b --- /dev/null +++ b/mwe/events/include/customTypes.h @@ -0,0 +1,35 @@ +#pragma once +#include <cmath> +struct Vector2 { + float x; // X component of the vector + float y; // Y component of the vector + + // Vector subtraction + Vector2 operator-(const Vector2 & other) const { return {x - other.x, y - other.y}; } + + // Vector addition + Vector2 operator+(const Vector2 & other) const { return {x + other.x, y + other.y}; } + + // Scalar multiplication + Vector2 operator*(float scalar) const { return {x * scalar, y * scalar}; } + + // Normalize the vector + Vector2 normalize() const { + float length = std::sqrt(x * x + y * y); + if (length == 0) return {0, 0}; // Prevent division by zero + return {x / length, y / length}; + } +}; +struct Collision { + int objectIdA; // ID of the first object + int objectIdB; // ID of the second object + Vector2 contactPoint; // Point of contact + Vector2 contactNormal; // Normal vector at the contact point + + // Constructor to initialize a Collision + Collision(int idA, int idB, const Vector2 & point, const Vector2 & normal, float depth) + : objectIdA(idA), + objectIdB(idB), + contactPoint(point), + contactNormal(normal) {} +}; diff --git a/mwe/events/include/event.h b/mwe/events/include/event.h new file mode 100644 index 0000000..ee1bf52 --- /dev/null +++ b/mwe/events/include/event.h @@ -0,0 +1,167 @@ +#pragma once +#include "customTypes.h" +#include "keyCodes.h" +#include <cstdint> +#include <iostream> +#include <string> +#include <unordered_map> +#include <variant> +class UUIDGenerator { +public: + static std::uint32_t getUniqueID() { + static std::uint32_t id = 0; + return ++id; + } +}; +#define REGISTER_EVENT_TYPE(ClassName) \ +\ +public: \ + static std::uint32_t getStaticEventType() { \ + static std::uint32_t typeID = UUIDGenerator::getUniqueID(); \ + return typeID; \ + } \ + virtual std::uint32_t getEventType() const override { return getStaticEventType(); } +class Event { +public: + Event(std::string eventType); + virtual ~Event() = default; + virtual std::uint32_t getEventType() const = 0; + virtual std::string toString() const; + void addArgument(const std::string & key, + const std::variant<int, std::string, float> & value); + + std::variant<int, std::string, float> getArgument(const std::string & key) const; + + std::string getType() const; + bool getHandled() const; + void markHandled(); + +private: + std::unordered_map<std::string, std::variant<int, std::string, float>> eventData; + bool isHandled = false; +}; + +// KeyPressedEvent class +class KeyPressedEvent : public Event { +public: + KeyPressedEvent(int keyCode); + + REGISTER_EVENT_TYPE("KeyPressedEvent"); + + Keycode getKeyCode() const; + int getRepeatCount() const; + +private: + Keycode keycode; + +public: + Keycode key = 0; + int repeatCount = 0; +}; +class MouseClickEvent : public Event { +public: + MouseClickEvent(int x, int y, MouseButton button); + + REGISTER_EVENT_TYPE("KeyClickedEvent"); + std::pair<int, int> getMousePosition() const; + MouseButton getButton() const { return button; } + +private: + int mouseX = 0; + int mouseY = 0; + MouseButton button; +}; +// KeyReleasedEvent class +class KeyReleasedEvent : public Event { +public: + KeyReleasedEvent(int keyCode); + + REGISTER_EVENT_TYPE(KeyReleasedEvent); + + Keycode getKeyCode() const; + +private: + Keycode key = 0; +}; + +// MousePressedEvent class +class MousePressedEvent : public Event { +public: + MousePressedEvent(int mouseX, int mouseY); + + REGISTER_EVENT_TYPE(MousePressedEvent) + + std::pair<int, int> getMousePosition() const; + +private: + int mouseX = 0; + int mouseY = 0; + MouseButton button; +}; +class MouseReleasedEvent : public Event { +public: + MouseReleasedEvent(int mouseX, int mouseY, MouseButton button); + + REGISTER_EVENT_TYPE(MouseReleasedEvent) + + std::pair<int, int> getMousePosition() const; + MouseButton getMouseButton() const; + +private: + int mouseX = 0; + int mouseY = 0; + MouseButton button; +}; +class MouseMovedEvent : public Event { +public: + MouseMovedEvent(int mouseX, int mouseY); + + REGISTER_EVENT_TYPE(MouseMovedEvent) + + std::pair<int, int> getMousePosition() const; + +private: + int mouseX = 0; + int mouseY = 0; +}; +class CollisionEvent : public Event { +public: + CollisionEvent(Collision); + + REGISTER_EVENT_TYPE(CollisionEvent) + + Collision getCollisionData() const; + +private: + Collision collisionData; +}; +class TextSubmitEvent : public Event { +public: + TextSubmitEvent(std::string submittedText); + + REGISTER_EVENT_TYPE(TextSubmitEvent) + + std::string getText() const; + +private: + std::string text; +}; +class ShutDownEvent : public Event { +public: + ShutDownEvent() : Event("ShutDownEvent") {}; + + REGISTER_EVENT_TYPE(ShutDownEvent) + +private: +}; +// class ButtonClickEvent : public Event { +// public: +// ButtonClickEvent(int x,int y,int width,int height); + +// REGISTER_EVENT_TYPE(TextSubmitEvent) + +// std::string getText() const; + +// private: +// std::string text; +// }; diff --git a/mwe/events/include/eventHandler.h b/mwe/events/include/eventHandler.h new file mode 100644 index 0000000..3a83b15 --- /dev/null +++ b/mwe/events/include/eventHandler.h @@ -0,0 +1,46 @@ +#pragma once +#include "event.h" +#include <functional> +#include <iostream> + +template <typename EventType> +using EventHandler = std::function<void(const EventType & e)>; + +class IEventHandlerWrapper { +public: + virtual ~IEventHandlerWrapper() = default; + + void exec(const Event & e); + + virtual std::string getType() const = 0; + virtual bool isDestroyOnSuccess() const = 0; + +private: + virtual void call(const Event & e) = 0; +}; + +template <typename EventType> +class EventHandlerWrapper : public IEventHandlerWrapper { +public: + explicit EventHandlerWrapper(const EventHandler<EventType> & handler, + const bool destroyOnSuccess = false) + : m_handler(handler), + m_handlerType(m_handler.target_type().name()), + m_destroyOnSuccess(destroyOnSuccess) { + // std::cout << m_handlerType << std::endl; + } + +private: + void call(const Event & e) override { + if (e.getEventType() == EventType::getStaticEventType()) { + m_handler(static_cast<const EventType &>(e)); + } + } + + std::string getType() const override { return m_handlerType; } + bool isDestroyOnSuccess() const { return m_destroyOnSuccess; } + + EventHandler<EventType> m_handler; + const std::string m_handlerType; + bool m_destroyOnSuccess{false}; +}; diff --git a/mwe/events/include/eventManager.h b/mwe/events/include/eventManager.h new file mode 100644 index 0000000..30e927f --- /dev/null +++ b/mwe/events/include/eventManager.h @@ -0,0 +1,60 @@ +#pragma once +#include "event.h" +#include "eventHandler.h" +#include "keyCodes.h" +#include <memory> +#include <unordered_map> +#include <vector> +// using EventType = std::uint32_t; +// using EventId = std::uint64_t; + +class EventManager { +public: + EventManager(const EventManager &) = delete; + const EventManager & operator=(const EventManager &) = delete; + static EventManager & getInstance() { + static EventManager instance; + return instance; + } + + void shutdown(); + void subscribe(int eventType, std::unique_ptr<IEventHandlerWrapper> && handler, + int eventId); + void unsubscribe(int eventType, const std::string & handlerName, int eventId); + void triggerEvent(const Event & event_, int eventId); + void queueEvent(std::unique_ptr<Event> && event_, int eventId); + void dispatchEvents(); + +private: + EventManager() = default; + std::vector<std::pair<std::unique_ptr<Event>, int>> eventsQueue; + std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>> subscribers; + std::unordered_map< + int, std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>> + subscribersByEventId; +}; + +template <typename EventType> +inline void subscribe(const EventHandler<EventType> & callback, int eventId = 0, + const bool unsubscribeOnSuccess = false) { + std::unique_ptr<IEventHandlerWrapper> handler + = std::make_unique<EventHandlerWrapper<EventType>>(callback, unsubscribeOnSuccess); + EventManager::getInstance().subscribe(EventType::getStaticEventType(), std::move(handler), + eventId); +} + +template <typename EventType> +inline void unsubscribe(const EventHandler<EventType> & callback, int eventId = 0) { + const std::string handlerName = callback.target_type().name(); + EventManager::getInstance().unsubscribe(EventType::getStaticEventType(), handlerName, + eventId); +} + +inline void triggerEvent(const Event & triggeredEvent, int eventId = 0) { + EventManager::getInstance().triggerEvent(triggeredEvent, eventId); +} + +inline void queueEvent(std::unique_ptr<Event> && queuedEvent, int eventId = 0) { + EventManager::getInstance().queueEvent(std::forward<std::unique_ptr<Event>>(queuedEvent), + eventId); +} diff --git a/mwe/events/include/gameObject.h b/mwe/events/include/gameObject.h new file mode 100644 index 0000000..48e239b --- /dev/null +++ b/mwe/events/include/gameObject.h @@ -0,0 +1,20 @@ +#pragma once +#include <cstdint> +#include <string> +class GameObject { +public: + GameObject() {} + + // template <typename... Args> + // void addSpriteComponent(Args &&... args); + // template <typename... Args> + // void addRigidbodyComponent(Args &&... args); + // template <typename... Args> + // void addColiderComponent(Args &&... args); + + std::uint32_t mId; + std::string mName; + std::string mTag; + bool mActive; + int mLayer; +}; diff --git a/mwe/events/include/iKeyListener.h b/mwe/events/include/iKeyListener.h new file mode 100644 index 0000000..5fee2eb --- /dev/null +++ b/mwe/events/include/iKeyListener.h @@ -0,0 +1,20 @@ +#pragma once +#include "event.h" +#include "eventHandler.h" +#include "eventManager.h" +class IKeyListener { +public: + virtual ~IKeyListener(); + virtual void onKeyPressed(const KeyPressedEvent & event) = 0; + virtual void onKeyReleased(const KeyReleasedEvent & event) = 0; + +protected: + void subscribeEvents(int listenerId = 0); + void unsubscribeEvents(int listenerId = 0); + void activate(int listenerId = 0) { subscribeEvents(listenerId); } + void deactivate(int listenerId = 0) { unsubscribeEvents(listenerId); } + +private: + EventHandler<KeyPressedEvent> keyPressedHandler; + EventHandler<KeyReleasedEvent> keyReleasedHandler; +}; diff --git a/mwe/events/include/iMouseListener.h b/mwe/events/include/iMouseListener.h new file mode 100644 index 0000000..5b1181c --- /dev/null +++ b/mwe/events/include/iMouseListener.h @@ -0,0 +1,24 @@ +#pragma once +#include "event.h" +#include "eventHandler.h" +#include "eventManager.h" + +class IMouseListener { +public: + virtual ~IMouseListener(); + + virtual void onMouseClicked(const MouseClickEvent & event) = 0; + virtual void onMousePressed(const MousePressedEvent & event) = 0; + virtual void onMouseReleased(const MouseReleasedEvent & event) = 0; + virtual void onMouseMoved(const MouseMovedEvent & event) = 0; + +protected: + void subscribeEvents(int listenerId = 0); + void unsubscribeEvents(int listenerId = 0); + +private: + EventHandler<MouseClickEvent> mouseClickHandler; + EventHandler<MousePressedEvent> mousePressHandler; + EventHandler<MouseReleasedEvent> mouseReleaseHandler; + EventHandler<MouseMovedEvent> mouseMoveHandler; +}; diff --git a/mwe/events/include/inputSystem.h b/mwe/events/include/inputSystem.h new file mode 100644 index 0000000..3e53b7c --- /dev/null +++ b/mwe/events/include/inputSystem.h @@ -0,0 +1,23 @@ +#pragma once +#include "event.h" +#include "eventManager.h" +#include "keyCodes.h" +#include "uiObject.h" +#include <vector> +class InputSystem { +public: + InputSystem(); + void registerButton(Button * button); + void registerText(Text * label); + void registerTextInput(TextInput * input); + void processInput(); + +private: + std::vector<Button *> buttons; + std::vector<TextInput *> textInputs; + std::vector<Text *> texts; + void processMouseClick(int mouseX, int mouseY); + void processInputField(int mouseX, int mouseY); + void processKeyPress(Keycode); + void processTextInput(const std::string & text); +}; diff --git a/mwe/events/include/keyCodes.h b/mwe/events/include/keyCodes.h new file mode 100644 index 0000000..73ba1cd --- /dev/null +++ b/mwe/events/include/keyCodes.h @@ -0,0 +1,154 @@ +#pragma once +#include <SDL2/SDL.h> +#include <cstdint> +#include <unordered_map> +using Keycode = uint16_t; +enum class MouseButton { + None = 0, + Left_Mouse = 1, + Right_Mouse = 2, + Middle_Mouse = 3, + X1_Mouse = 4, + X2_Mouse = 5, + Scroll_Up = 6, + Scroll_Down = 7, +}; +enum : Keycode { + // From glfw3.h + Space = 32, + Apostrophe = 39, /* ' */ + Comma = 44, /* , */ + Minus = 45, /* - */ + Period = 46, /* . */ + Slash = 47, /* / */ + + D0 = 48, /* 0 */ + D1 = 49, /* 1 */ + D2 = 50, /* 2 */ + D3 = 51, /* 3 */ + D4 = 52, /* 4 */ + D5 = 53, /* 5 */ + D6 = 54, /* 6 */ + D7 = 55, /* 7 */ + D8 = 56, /* 8 */ + D9 = 57, /* 9 */ + + Semicolon = 59, /* ; */ + Equal = 61, /* = */ + + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, + + LeftBracket = 91, /* [ */ + Backslash = 92, /* \ */ + RightBracket = 93, /* ] */ + GraveAccent = 96, /* ` */ + + World1 = 161, /* non-US #1 */ + World2 = 162, /* non-US #2 */ + + /* Function keys */ + Escape = 256, + Enter = 257, + Tab = 258, + Backspace = 259, + Insert = 260, + Delete = 261, + Right = 262, + Left = 263, + Down = 264, + Up = 265, + PageUp = 266, + PageDown = 267, + Home = 268, + End = 269, + CapsLock = 280, + ScrollLock = 281, + NumLock = 282, + PrintScreen = 283, + Pause = 284, + F1 = 290, + F2 = 291, + F3 = 292, + F4 = 293, + F5 = 294, + F6 = 295, + F7 = 296, + F8 = 297, + F9 = 298, + F10 = 299, + F11 = 300, + F12 = 301, + F13 = 302, + F14 = 303, + F15 = 304, + F16 = 305, + F17 = 306, + F18 = 307, + F19 = 308, + F20 = 309, + F21 = 310, + F22 = 311, + F23 = 312, + F24 = 313, + F25 = 314, + + /* Keypad */ + KP0 = 320, + KP1 = 321, + KP2 = 322, + KP3 = 323, + KP4 = 324, + KP5 = 325, + KP6 = 326, + KP7 = 327, + KP8 = 328, + KP9 = 329, + KPDecimal = 330, + KPDivide = 331, + KPMultiply = 332, + KPSubtract = 333, + KPAdd = 334, + KPEnter = 335, + KPEqual = 336, + + LeftShift = 340, + LeftControl = 341, + LeftAlt = 342, + LeftSuper = 343, + RightShift = 344, + RightControl = 345, + RightAlt = 346, + RightSuper = 347, + Menu = 348 +}; + +// Define the mapping +extern const std::unordered_map<SDL_Keycode, Keycode> sdlToCustom; + +// Function to map SDL_Keycode to custom Keycode +Keycode getCustomKey(SDL_Keycode sdlKey); diff --git a/mwe/events/include/keyListenerTest.h b/mwe/events/include/keyListenerTest.h new file mode 100644 index 0000000..08f3feb --- /dev/null +++ b/mwe/events/include/keyListenerTest.h @@ -0,0 +1,12 @@ +#pragma once +#include "iKeyListener.h" +#include <iostream> + +class KeyListenerTest : public IKeyListener { +public: + KeyListenerTest(int listenerId); + ~KeyListenerTest(); + + void onKeyPressed(const KeyPressedEvent & event) override; + void onKeyReleased(const KeyReleasedEvent & event) override; +}; diff --git a/mwe/events/include/loopManager.h b/mwe/events/include/loopManager.h new file mode 100644 index 0000000..9959c94 --- /dev/null +++ b/mwe/events/include/loopManager.h @@ -0,0 +1,36 @@ +#pragma once +#include "timer.h" +#include "window.h" +#include <SDL2/SDL.h> +//#include "combinedEvent.h" +#include "eventHandler.h" +#include "eventManager.h" +#include "inputSystem.h" +#include "loopManager.h" +#include "uiObject.h" +#include "uiRenderer.h" +#include <memory> +class LoopManager { +public: + LoopManager(); + void setup(); + void loop(); + void setRunning(bool running); + +private: + void processInput(); + void update(); + void lateUpdate(); + void fixedUpdate(); + void render(); + void onShutdown(const ShutDownEvent & e); + bool gameRunning = false; + WindowManager window; + int timeScale = 1; + float accumulator = 0.0; + double currentTime; + double t = 0.0; + double dt = 0.01; + std::unique_ptr<InputSystem> inputSystem; + EventHandler<ShutDownEvent> shutdownHandler; +}; diff --git a/mwe/events/include/mouseListenerTest.h b/mwe/events/include/mouseListenerTest.h new file mode 100644 index 0000000..ca9afc5 --- /dev/null +++ b/mwe/events/include/mouseListenerTest.h @@ -0,0 +1,14 @@ +#pragma once +#include "iMouseListener.h" +#include <iostream> + +class MouseListenerTest : public IMouseListener { +public: + MouseListenerTest(int listenerId); + ~MouseListenerTest(); + + void onMouseClicked(const MouseClickEvent & event) override; + void onMousePressed(const MousePressedEvent & event) override; + void onMouseReleased(const MouseReleasedEvent & event) override; + void onMouseMoved(const MouseMovedEvent & event) override; +}; diff --git a/mwe/events/include/timer.h b/mwe/events/include/timer.h new file mode 100644 index 0000000..22383b2 --- /dev/null +++ b/mwe/events/include/timer.h @@ -0,0 +1,31 @@ +#pragma once + +#include <SDL2/SDL.h> + +class LoopTimer { +public: + static LoopTimer & getInstance(); + void start(); + void update(); + double getDeltaTime() const; + int getCurrentTime() const; + void advanceFixedUpdate(); + double getFixedDeltaTime() const; + void setFPS(int FPS); + int getFPS() const; + void enforceFrameRate(); + double getLag() const; + +private: + LoopTimer(); + int FPS = 50; + double gameScale = 1; + double maximumDeltaTime = 0.25; + double deltaTime; + double frameTargetTime = FPS / 1000; + double fixedDeltaTime = 0.01; + double elapsedTime; + double elapsedFixedTime; + double time; + uint64_t lastFrameTime; +}; diff --git a/mwe/events/include/uiObject.h b/mwe/events/include/uiObject.h new file mode 100644 index 0000000..23efe44 --- /dev/null +++ b/mwe/events/include/uiObject.h @@ -0,0 +1,68 @@ +#pragma once +#include "event.h" +#include "eventHandler.h" +#include "gameObject.h" +#include <SDL2/SDL.h> +#include <SDL_ttf.h> +#include <functional> +struct Alignment { + enum class Horizontal { LEFT, CENTER, RIGHT }; + enum class Vertical { TOP, MIDDLE, BOTTOM }; + enum class PositioningMode { RELATIVE, STATIC, ABSOLUTE }; + + Horizontal horizontal = Horizontal::CENTER; + Vertical vertical = Vertical::MIDDLE; + PositioningMode mode = PositioningMode::RELATIVE; + + int staticX = 0; + int staticY = 0; + + int marginTop = 0; + int marginBottom = 0; + int marginLeft = 0; + int marginRight = 0; +}; +struct RGBColor { + int red; + int green; + int blue; +}; +class UIObject : public GameObject { +public: + UIObject(int width, int height); + virtual ~UIObject() {} + int width; + int height; + int x; + int y; +}; +class Button : public UIObject { +public: + Button(int width, int height); + RGBColor color; + std::function<void()> onClick; +}; +class Text : public UIObject { +public: + Text(int width, int height); + std::string text; + int size; + Alignment alignment; + //font resource + TTF_Font * font; + RGBColor color; +}; +class TextInput : public UIObject { +public: + TextInput(int width, int height); + std::string textBuffer; + std::string placeholder; + bool isActive = false; + RGBColor textColor; + RGBColor backgroundColor; + size_t maxLength = 100; + Alignment alignment; + TTF_Font * font = nullptr; + std::function<void()> onSubmit; + std::function<void()> onFocus; +}; diff --git a/mwe/events/include/uiRenderer.h b/mwe/events/include/uiRenderer.h new file mode 100644 index 0000000..8f22fdf --- /dev/null +++ b/mwe/events/include/uiRenderer.h @@ -0,0 +1,21 @@ +#pragma once +#include "uiObject.h" +#include <SDL2/SDL.h> +#include <SDL2/SDL_ttf.h> +#include <string> + +class UIRenderer { +public: + UIRenderer(SDL_Renderer * renderer); + ~UIRenderer(); + + void render(UIObject * uiObject); + +private: + SDL_Renderer * renderer; + TTF_Font * font; + + void renderButton(Button * button); + void renderText(Text * text); + void renderTextInput(TextInput * textInput); +}; diff --git a/mwe/events/include/userevent.h b/mwe/events/include/userevent.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mwe/events/include/userevent.h diff --git a/mwe/events/include/window.h b/mwe/events/include/window.h new file mode 100644 index 0000000..bd75c4a --- /dev/null +++ b/mwe/events/include/window.h @@ -0,0 +1,27 @@ +#pragma once +#include "uiObject.h" +#include "uiRenderer.h" +#include <SDL2/SDL.h> +#include <vector> + +class WindowManager { +public: + WindowManager(); + virtual ~WindowManager(); + + bool initWindow(); + void destroyWindow(); + SDL_Renderer * getRenderer(); + + void addUIObject(UIObject * uiObject); + void renderUIObjects(); + +private: + const int SCREEN_WIDTH = 800; + const int SCREEN_HEIGHT = 600; + SDL_Window * window = nullptr; + SDL_Renderer * renderer = nullptr; + + UIRenderer * uiRenderer; + std::vector<UIObject *> uiObjects; +}; diff --git a/mwe/events/src/event.cpp b/mwe/events/src/event.cpp new file mode 100644 index 0000000..0040c73 --- /dev/null +++ b/mwe/events/src/event.cpp @@ -0,0 +1,71 @@ +#include "event.h" +#include "keyCodes.h" +// Event class methods +Event::Event(std::string eventType) { eventData["eventType"] = eventType; } + +void Event::addArgument(const std::string & key, + const std::variant<int, std::string, float> & value) { + eventData[key] = value; +} + +std::variant<int, std::string, float> Event::getArgument(const std::string & key) const { + return eventData.at(key); +} + +std::string Event::getType() const { return std::get<std::string>(eventData.at("eventType")); } +std::string Event::toString() const { return std::to_string(getEventType()); } +bool Event::getHandled() const { return isHandled; } + +void Event::markHandled() { isHandled = true; } + +// KeyPressedEvent class methods +KeyPressedEvent::KeyPressedEvent(int keycode) + : Event("KeyPressedEvent"), + key(keycode), + repeatCount(0) {} + +Keycode KeyPressedEvent::getKeyCode() const { return key; } + +int KeyPressedEvent::getRepeatCount() const { return repeatCount; } + +// KeyReleasedEvent class methods +KeyReleasedEvent::KeyReleasedEvent(int keycode) : Event("KeyReleasedEvent"), key(keycode) {} + +Keycode KeyReleasedEvent::getKeyCode() const { return key; } + +// MousePressedEvent class methods +MousePressedEvent::MousePressedEvent(int mouseX, int mouseY) + : Event("MousePressedEvent"), + mouseX(mouseX), + mouseY(mouseY) {} + +std::pair<int, int> MousePressedEvent::getMousePosition() const { return {mouseX, mouseY}; } + +//Collision event +CollisionEvent::CollisionEvent(Collision collision) + : collisionData(collision), + Event("CollisionEvent") {} + +Collision CollisionEvent::getCollisionData() const { return this->collisionData; } + +TextSubmitEvent::TextSubmitEvent(std::string text) : text(text), Event("TextSubmitEvent") {} + +std::string TextSubmitEvent::getText() const { return this->text; } + +MouseReleasedEvent::MouseReleasedEvent(int x, int y, MouseButton button) + : mouseX(x), + mouseY(y), + button(button), + Event("MouseReleased") {} +std::pair<int, int> MouseReleasedEvent::getMousePosition() const { return {mouseX, mouseY}; } +MouseClickEvent::MouseClickEvent(int x, int y, MouseButton button) + : mouseX(x), + mouseY(y), + button(button), + Event("MouseClickEvent") {} +MouseMovedEvent::MouseMovedEvent(int x, int y) + : mouseX(x), + mouseY(y), + Event("MouseMovedEvent") {} +std::pair<int, int> MouseClickEvent::getMousePosition() const { return {mouseX, mouseY}; } +std::pair<int, int> MouseMovedEvent::getMousePosition() const { return {mouseX, mouseY}; } diff --git a/mwe/events/src/eventHandler.cpp b/mwe/events/src/eventHandler.cpp new file mode 100644 index 0000000..7fb8d70 --- /dev/null +++ b/mwe/events/src/eventHandler.cpp @@ -0,0 +1,2 @@ +#include "eventHandler.h" +void IEventHandlerWrapper::exec(const Event & e) { call(e); } diff --git a/mwe/events/src/eventManager.cpp b/mwe/events/src/eventManager.cpp new file mode 100644 index 0000000..9e7d880 --- /dev/null +++ b/mwe/events/src/eventManager.cpp @@ -0,0 +1,115 @@ +#include "eventManager.h" + +void EventManager::shutdown() { subscribers.clear(); } + +void EventManager::subscribe(int eventType, std::unique_ptr<IEventHandlerWrapper> && handler, + int eventId) { + if (eventId) { + std::unordered_map< + int, std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>>:: + iterator subscribers + = subscribersByEventId.find(eventType); + + if (subscribers != subscribersByEventId.end()) { + std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>> & + handlersMap + = subscribers->second; + std::unordered_map< + int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator handlers + = handlersMap.find(eventId); + if (handlers != handlersMap.end()) { + handlers->second.emplace_back(std::move(handler)); + return; + } + } + subscribersByEventId[eventType][eventId].emplace_back(std::move(handler)); + + } else { + auto & handlers = subscribers[eventType]; + handlers.emplace_back(std::move(handler)); + } +} + +void EventManager::unsubscribe(int eventType, const std::string & handlerName, int eventId) { + if (eventId) { + std::unordered_map< + int, std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>>:: + iterator subscriberList + = subscribersByEventId.find(eventType); + if (subscriberList != subscribersByEventId.end()) { + std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>> & + handlersMap + = subscriberList->second; + std::unordered_map< + int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator handlers + = handlersMap.find(eventId); + if (handlers != handlersMap.end()) { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & callbacks + = handlers->second; + for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it + = callbacks.begin(); + it != callbacks.end(); ++it) { + if (it->get()->getType() == handlerName) { + it = callbacks.erase(it); + return; + } + } + } + } + } else { + std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator + handlersIt + = subscribers.find(eventType); + if (handlersIt != subscribers.end()) { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & handlers = handlersIt->second; + for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it + = handlers.begin(); + it != handlers.end(); ++it) { + if (it->get()->getType() == handlerName) { + it = handlers.erase(it); + return; + } + } + } + } +} + +void EventManager::triggerEvent(const Event & event_, int eventId) { + if (eventId > 0) { + auto handlersIt = subscribersByEventId[event_.getEventType()].find(eventId); + if (handlersIt != subscribersByEventId[event_.getEventType()].end()) { + std::vector<std::unique_ptr<IEventHandlerWrapper>> & callbacks + = handlersIt->second; + for (auto it = callbacks.begin(); it != callbacks.end();) { + (*it)->exec(event_); + if ((*it)->isDestroyOnSuccess()) { + it = callbacks.erase(it); + } else { + ++it; + } + } + } + } else { + auto & handlers = subscribers[event_.getEventType()]; + for (std::unique_ptr<IEventHandlerWrapper> & handler : handlers) { + handler->exec(event_); + } + } +} + +void EventManager::queueEvent(std::unique_ptr<Event> && event_, int eventId) { + eventsQueue.emplace_back(std::move(event_), eventId); +} + +void EventManager::dispatchEvents() { + for (std::vector<std::pair<std::unique_ptr<Event>, int>>::iterator eventIt + = eventsQueue.begin(); + eventIt != eventsQueue.end();) { + if (!eventIt->first.get()->getHandled()) { + triggerEvent(*eventIt->first.get(), eventIt->second); + eventIt = eventsQueue.erase(eventIt); + } else { + ++eventIt; + } + } +} diff --git a/mwe/events/src/iKeyListener.cpp b/mwe/events/src/iKeyListener.cpp new file mode 100644 index 0000000..d5d1d90 --- /dev/null +++ b/mwe/events/src/iKeyListener.cpp @@ -0,0 +1,17 @@ +#include "iKeyListener.h" + +IKeyListener::~IKeyListener() { unsubscribeEvents(); } + +void IKeyListener::subscribeEvents(int listenerId) { + keyPressedHandler = [this](const KeyPressedEvent & event) { this->onKeyPressed(event); }; + keyReleasedHandler + = [this](const KeyReleasedEvent & event) { this->onKeyReleased(event); }; + + subscribe<KeyPressedEvent>(keyPressedHandler, listenerId); + subscribe<KeyReleasedEvent>(keyReleasedHandler, listenerId); +} + +void IKeyListener::unsubscribeEvents(int listenerId) { + unsubscribe<KeyPressedEvent>(keyPressedHandler, listenerId); + unsubscribe<KeyReleasedEvent>(keyReleasedHandler, listenerId); +} diff --git a/mwe/events/src/iMouseListener.cpp b/mwe/events/src/iMouseListener.cpp new file mode 100644 index 0000000..53e6f80 --- /dev/null +++ b/mwe/events/src/iMouseListener.cpp @@ -0,0 +1,23 @@ +#include "iMouseListener.h" +IMouseListener::~IMouseListener() { unsubscribeEvents(); } + +void IMouseListener::subscribeEvents(int listenerId) { + mouseClickHandler = [this](const MouseClickEvent & event) { this->onMouseClicked(event); }; + mousePressHandler + = [this](const MousePressedEvent & event) { this->onMousePressed(event); }; + mouseReleaseHandler + = [this](const MouseReleasedEvent & event) { this->onMouseReleased(event); }; + mouseMoveHandler = [this](const MouseMovedEvent & event) { this->onMouseMoved(event); }; + + subscribe<MouseClickEvent>(mouseClickHandler, listenerId); + subscribe<MousePressedEvent>(mousePressHandler, listenerId); + subscribe<MouseReleasedEvent>(mouseReleaseHandler, listenerId); + subscribe<MouseMovedEvent>(mouseMoveHandler, listenerId); +} + +void IMouseListener::unsubscribeEvents(int listenerId) { + unsubscribe<MouseClickEvent>(mouseClickHandler, listenerId); + unsubscribe<MousePressedEvent>(mousePressHandler, listenerId); + unsubscribe<MouseReleasedEvent>(mouseReleaseHandler, listenerId); + unsubscribe<MouseMovedEvent>(mouseMoveHandler, listenerId); +} diff --git a/mwe/events/src/inputSystem.cpp b/mwe/events/src/inputSystem.cpp new file mode 100644 index 0000000..d740c9e --- /dev/null +++ b/mwe/events/src/inputSystem.cpp @@ -0,0 +1,91 @@ +#include "inputSystem.h" + +InputSystem::InputSystem() {} + +void InputSystem::registerButton(Button * button) { buttons.push_back(button); } +void InputSystem::registerTextInput(TextInput * input) { textInputs.push_back(input); } +void InputSystem::registerText(Text * label) { texts.push_back(label); } + +void InputSystem::processInput() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + triggerEvent(ShutDownEvent()); + break; + case SDL_KEYDOWN: + triggerEvent(KeyPressedEvent(getCustomKey(event.key.keysym.sym))); + processKeyPress(event.key.keysym.sym); + break; + case SDL_TEXTINPUT: + // Process typed characters + processTextInput(event.text.text); + break; + case SDL_MOUSEBUTTONDOWN: { + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); + processMouseClick(mouseX, mouseY); + triggerEvent(MousePressedEvent(mouseX, mouseY)); + break; + } + } + } +} + +void InputSystem::processMouseClick(int mouseX, int mouseY) { + for (auto * button : buttons) { + if (mouseX >= button->x && mouseX <= (button->x + button->width) && mouseY >= button->y + && mouseY <= (button->y + button->height)) { + button->onClick(); + } + } + for (auto * textInput : textInputs) { + if (mouseX >= textInput->x && mouseX <= textInput->x + textInput->width + && mouseY >= textInput->y && mouseY <= textInput->y + textInput->height) { + textInput->isActive = true; + } else { + textInput->isActive = false; + } + } +} +void InputSystem::processKeyPress(Keycode key) { + // for (auto* textInput : textInputs) { + // if (textInput->isActive) { + // if (key == SDLK_RETURN || key == SDLK_KP_ENTER) { + // // Submit the text + // if (textInput->onSubmit) { + // textInput->onSubmit(); + // } + // } + // else if (key == SDLK_BACKSPACE) { + // // Handle backspace + // if (!textInput->textBuffer.empty() && textInput->caretPosition > 0) { + // textInput->textBuffer.erase(textInput->caretPosition - 1, 1); + // textInput->caretPosition--; + // } + // } + // else if (key == SDLK_LEFT) { + // // Move caret left + // if (textInput->caretPosition > 0) { + // textInput->caretPosition--; + // } + // } + // else if (key == SDLK_RIGHT) { + // // Move caret right + // if (textInput->caretPosition < textInput->textBuffer.size()) { + // textInput->caretPosition++; + // } + // } + // } + // } +} + +void InputSystem::processTextInput(const std::string & text) { + // for (auto* textInput : textInputs) { + // if (textInput->isActive) { + // // Insert text at caret position + // textInput->textBuffer.insert(textInput->caretPosition, text); + // textInput->caretPosition += text.length(); + // } + // } +} diff --git a/mwe/events/src/keyCodes.cpp b/mwe/events/src/keyCodes.cpp new file mode 100644 index 0000000..5f3aa96 --- /dev/null +++ b/mwe/events/src/keyCodes.cpp @@ -0,0 +1,139 @@ +#include "keyCodes.h" + +const std::unordered_map<SDL_Keycode, Keycode> sdlToCustom + = {{SDLK_SPACE, Space}, + {SDLK_QUOTE, Apostrophe}, + {SDLK_COMMA, Comma}, + {SDLK_MINUS, Minus}, + {SDLK_PERIOD, Period}, + {SDLK_SLASH, Slash}, + + {SDLK_0, D0}, + {SDLK_1, D1}, + {SDLK_2, D2}, + {SDLK_3, D3}, + {SDLK_4, D4}, + {SDLK_5, D5}, + {SDLK_6, D6}, + {SDLK_7, D7}, + {SDLK_8, D8}, + {SDLK_9, D9}, + + {SDLK_SEMICOLON, Semicolon}, + {SDLK_EQUALS, Equal}, + + {SDLK_a, A}, + {SDLK_b, B}, + {SDLK_c, C}, + {SDLK_d, D}, + {SDLK_e, E}, + {SDLK_f, F}, + {SDLK_g, G}, + {SDLK_h, H}, + {SDLK_i, I}, + {SDLK_j, J}, + {SDLK_k, K}, + {SDLK_l, L}, + {SDLK_m, M}, + {SDLK_n, N}, + {SDLK_o, O}, + {SDLK_p, P}, + {SDLK_q, Q}, + {SDLK_r, R}, + {SDLK_s, S}, + {SDLK_t, T}, + {SDLK_u, U}, + {SDLK_v, V}, + {SDLK_w, W}, + {SDLK_x, X}, + {SDLK_y, Y}, + {SDLK_z, Z}, + + {SDLK_LEFTBRACKET, LeftBracket}, + {SDLK_BACKSLASH, Backslash}, + {SDLK_RIGHTBRACKET, RightBracket}, + {SDLK_BACKQUOTE, GraveAccent}, + + {SDLK_ESCAPE, Escape}, + {SDLK_RETURN, Enter}, + {SDLK_TAB, Tab}, + {SDLK_BACKSPACE, Backspace}, + {SDLK_INSERT, Insert}, + {SDLK_DELETE, Delete}, + {SDLK_RIGHT, Right}, + {SDLK_LEFT, Left}, + {SDLK_DOWN, Down}, + {SDLK_UP, Up}, + {SDLK_PAGEUP, PageUp}, + {SDLK_PAGEDOWN, PageDown}, + {SDLK_HOME, Home}, + {SDLK_END, End}, + + {SDLK_CAPSLOCK, CapsLock}, + {SDLK_SCROLLLOCK, ScrollLock}, + {SDLK_NUMLOCKCLEAR, NumLock}, + {SDLK_PRINTSCREEN, PrintScreen}, + {SDLK_PAUSE, Pause}, + + {SDLK_F1, F1}, + {SDLK_F2, F2}, + {SDLK_F3, F3}, + {SDLK_F4, F4}, + {SDLK_F5, F5}, + {SDLK_F6, F6}, + {SDLK_F7, F7}, + {SDLK_F8, F8}, + {SDLK_F9, F9}, + {SDLK_F10, F10}, + {SDLK_F11, F11}, + {SDLK_F12, F12}, + {SDLK_F13, F13}, + {SDLK_F14, F14}, + {SDLK_F15, F15}, + {SDLK_F16, F16}, + {SDLK_F17, F17}, + {SDLK_F18, F18}, + {SDLK_F19, F19}, + {SDLK_F20, F20}, + {SDLK_F21, F21}, + {SDLK_F22, F22}, + {SDLK_F23, F23}, + {SDLK_F24, F24}, + + {SDLK_KP_0, KP0}, + {SDLK_KP_1, KP1}, + {SDLK_KP_2, KP2}, + {SDLK_KP_3, KP3}, + {SDLK_KP_4, KP4}, + {SDLK_KP_5, KP5}, + {SDLK_KP_6, KP6}, + {SDLK_KP_7, KP7}, + {SDLK_KP_8, KP8}, + {SDLK_KP_9, KP9}, + + {SDLK_KP_DECIMAL, KPDecimal}, + {SDLK_KP_DIVIDE, KPDivide}, + {SDLK_KP_MULTIPLY, KPMultiply}, + {SDLK_KP_MINUS, KPSubtract}, + {SDLK_KP_PLUS, KPAdd}, + {SDLK_KP_ENTER, KPEnter}, + {SDLK_KP_EQUALS, KPEqual}, + + {SDLK_LSHIFT, LeftShift}, + {SDLK_LCTRL, LeftControl}, + {SDLK_LALT, LeftAlt}, + {SDLK_LGUI, LeftSuper}, + + {SDLK_RSHIFT, RightShift}, + {SDLK_RCTRL, RightControl}, + {SDLK_RALT, RightAlt}, + {SDLK_RGUI, RightSuper}, + + {SDLK_MENU, Menu}}; +Keycode getCustomKey(SDL_Keycode sdlKey) { + auto it = sdlToCustom.find(sdlKey); + if (it != sdlToCustom.end()) { + return it->second; + } + return 0; +} diff --git a/mwe/events/src/keyListenerTest.cpp b/mwe/events/src/keyListenerTest.cpp new file mode 100644 index 0000000..f45dffd --- /dev/null +++ b/mwe/events/src/keyListenerTest.cpp @@ -0,0 +1,13 @@ +#include "keyListenerTest.h" + +KeyListenerTest::KeyListenerTest(int listenerId) { subscribeEvents(listenerId); } + +KeyListenerTest::~KeyListenerTest() { unsubscribeEvents(); } + +void KeyListenerTest::onKeyPressed(const KeyPressedEvent & event) { + std::cout << "Key pressed: " << event.getKeyCode() << std::endl; +} + +void KeyListenerTest::onKeyReleased(const KeyReleasedEvent & event) { + std::cout << "Key released: " << event.getKeyCode() << std::endl; +} diff --git a/mwe/events/src/loopManager.cpp b/mwe/events/src/loopManager.cpp new file mode 100644 index 0000000..c58a5e7 --- /dev/null +++ b/mwe/events/src/loopManager.cpp @@ -0,0 +1,99 @@ +#include "loopManager.h" + +LoopManager::LoopManager() : inputSystem(std::make_unique<InputSystem>()) { + shutdownHandler = [this](const ShutDownEvent & event) { this->onShutdown(event); }; + subscribe(shutdownHandler); +} +void LoopManager::processInput() { + inputSystem->processInput(); + // SDL_Event event; + // SDL_PollEvent(&event); + // switch (event.type) { + // case SDL_QUIT: + // gameRunning = false; + // break; + // case SDL_KEYDOWN: + // triggerEvent(KeyPressedEvent(getCustomKey(event.key.keysym.sym))); + // break; + // case SDL_MOUSEBUTTONDOWN: + // int x, y; + // SDL_GetMouseState(&x, &y); + // triggerEvent(MousePressedEvent(x, y)); + // break; + // } +} +void LoopManager::setRunning(bool running) { this->gameRunning = running; } +void LoopManager::fixedUpdate() { + //fprintf(stderr, "fixed update\n"); +} +void LoopManager::loop() { + LoopTimer & timer = LoopTimer::getInstance(); + timer.start(); + + while (gameRunning) { + timer.update(); + processInput(); + while (timer.getLag() >= timer.getFixedDeltaTime()) { + fixedUpdate(); + timer.advanceFixedUpdate(); + } + + update(); + render(); + + timer.enforceFrameRate(); + } + + window.destroyWindow(); +} +void onKey(const KeyPressedEvent & e) { + int keyCode = e.getKeyCode(); + std::cout << "keycode pressed: " << keyCode << std::endl; +} +void onMouse(const MousePressedEvent & e) { + fprintf(stderr, "mouse Position X: %d Y: %d\n", e.getMousePosition().first, + e.getMousePosition().second); +} +void LoopManager::setup() { + gameRunning = window.initWindow(); + LoopTimer::getInstance().start(); + LoopTimer::getInstance().setFPS(50); + EventHandler<KeyPressedEvent> callback = onKey; + subscribe<KeyPressedEvent>(callback, false); + EventHandler<MousePressedEvent> mouseCallback = onMouse; + subscribe<MousePressedEvent>(mouseCallback, false); + EventHandler<KeyPressedEvent> closeWindowCallback = [this](const KeyPressedEvent & e) { + if (e.getKeyCode() == Escape) { + this->setRunning(false); + } + }; + subscribe<KeyPressedEvent>(closeWindowCallback, false); + Button * testButton = new Button(200, 200); + testButton->color = {100, 0, 100}; + testButton->onClick = []() { std::cout << "Button was clicked" << std::endl; }; + testButton->x = 200; + testButton->y = 200; + inputSystem->registerButton(testButton); + + window.addUIObject(testButton); + + TextInput * testInput = new TextInput(200, 200); + testInput->x = 100; + testInput->y = 100; + testInput->backgroundColor = {20, 50, 80}; + inputSystem->registerTextInput(testInput); + window.addUIObject(testInput); +} +void LoopManager::render() { + //fprintf(stderr, "**********render********** \n"); + if (gameRunning) { + window.renderUIObjects(); + } +} +void LoopManager::onShutdown(const ShutDownEvent & e) { this->gameRunning = false; } +void LoopManager::update() { + //fprintf(stderr, "**********normal update********** \n"); + LoopTimer & timer = LoopTimer::getInstance(); + + float delta = timer.getDeltaTime(); +} diff --git a/mwe/events/src/main.cpp b/mwe/events/src/main.cpp new file mode 100644 index 0000000..ad0fd69 --- /dev/null +++ b/mwe/events/src/main.cpp @@ -0,0 +1,86 @@ +#include "customTypes.h" +#include "event.h" +#include "iKeyListener.h" +#include "iMouseListener.h" +#include "keyListenerTest.h" +#include "loopManager.h" +#include "mouseListenerTest.h" +#include <SDL2/SDL.h> +#include <iostream> +#include <memory> +class PlayerDamagedEvent : public Event { +public: + PlayerDamagedEvent(int damage, int playerID) + : Event("PlayerDamaged"), + damage(damage), + playerID(playerID) {} + + REGISTER_EVENT_TYPE(PlayerDamagedEvent); + + int getDamage() const { return damage; } + int getPlayerID() const { return playerID; } + +private: + int damage; + int playerID; +}; +void onPlayerDamaged(const PlayerDamagedEvent & e) { + std::cout << "Player " << e.getPlayerID() << " took " << e.getDamage() << " damage." + << std::endl; +} + +void onKeyPressed1(const KeyPressedEvent & e) { + int keyCode = e.getKeyCode(); + fprintf(stderr, "first function KeyCode %d\n", keyCode); +} +void onKeyPressed(const KeyPressedEvent & e) { + int keyCode = e.getKeyCode(); + fprintf(stderr, "second function KeyCode %d\n", keyCode); +} +void CollisionHandler(const CollisionEvent & e) { + std::cout << "collision betwee object id: " << e.getCollisionData().objectIdA + << " and id: " << e.getCollisionData().objectIdB << std::endl; +} +void testCollisionEvent() { + Collision testCollision(1, 2, {3, 4}, {5, 6}, 7.8f); + subscribe<CollisionEvent>(CollisionHandler, 1); + // EventHandler<PlayerDamagedEvent> + triggerEvent(CollisionEvent(testCollision), 1); +} +int main(int argc, char * args[]) { + LoopManager gameLoop; + int testListenerId = 0; + KeyListenerTest keyListener(testListenerId); + MouseListenerTest mouseListener(testListenerId); + // custom event class poc + subscribe<PlayerDamagedEvent>(onPlayerDamaged); + triggerEvent(PlayerDamagedEvent(50, 1)); + subscribe<KeyPressedEvent>(onKeyPressed, 1, false); + subscribe<KeyPressedEvent>(onKeyPressed1, false); + // queueEvent(std::move(anotherKeyPressEvent)); + triggerEvent(KeyPressedEvent(42), 1); + + EventManager::getInstance().dispatchEvents(); + //collision event call + testCollisionEvent(); + + gameLoop.setup(); + gameLoop.loop(); + return 0; +} +// void collisionUpdate(){ +// int count; +// //iedere collision +// for (int i = 0; i < count; i++) +// { +// //trigger object 1 +// //triger object 2 +// triggerEvent(CollisionEvent(1,2),1); +// triggerEvent(CollisionEvent(1,2),2); +// } + +// } +// int main(){ + +// return 0; +// } diff --git a/mwe/events/src/mouseListenerTest.cpp b/mwe/events/src/mouseListenerTest.cpp new file mode 100644 index 0000000..7b35f4e --- /dev/null +++ b/mwe/events/src/mouseListenerTest.cpp @@ -0,0 +1,25 @@ +#include "mouseListenerTest.h" + +MouseListenerTest::MouseListenerTest(int listenerId) { subscribeEvents(listenerId); } + +MouseListenerTest::~MouseListenerTest() { unsubscribeEvents(); } + +void MouseListenerTest::onMouseClicked(const MouseClickEvent & event) { + std::cout << "Mouse clicked at: (" << event.getMousePosition().first << ", " + << event.getMousePosition().second << ")" << std::endl; +} + +void MouseListenerTest::onMousePressed(const MousePressedEvent & event) { + std::cout << "Mouse button pressed at: (" << event.getMousePosition().first << ", " + << event.getMousePosition().second << ")" << std::endl; +} + +void MouseListenerTest::onMouseReleased(const MouseReleasedEvent & event) { + std::cout << "Mouse button released at: (" << event.getMousePosition().first << ", " + << event.getMousePosition().second << ")" << std::endl; +} + +void MouseListenerTest::onMouseMoved(const MouseMovedEvent & event) { + std::cout << "Mouse moved to: (" << event.getMousePosition().first << ", " + << event.getMousePosition().second << ")" << std::endl; +} diff --git a/mwe/events/src/timer.cpp b/mwe/events/src/timer.cpp new file mode 100644 index 0000000..0f8339f --- /dev/null +++ b/mwe/events/src/timer.cpp @@ -0,0 +1,52 @@ +#include "timer.h" + +LoopTimer::LoopTimer() {} +LoopTimer & LoopTimer::getInstance() { + static LoopTimer instance; + return instance; +} + +void LoopTimer::start() { + lastFrameTime = SDL_GetTicks64(); + elapsedTime = 0; + elapsedFixedTime = 0; + deltaTime = 0; +} + +// Update the timer, calculate deltaTime +void LoopTimer::update() { + uint64_t currentFrameTime = SDL_GetTicks64(); + deltaTime = (currentFrameTime - lastFrameTime) / 1000.0; + + if (deltaTime > maximumDeltaTime) { + deltaTime = maximumDeltaTime; + } + + elapsedTime += deltaTime; + lastFrameTime = currentFrameTime; +} + +double LoopTimer::getDeltaTime() const { return deltaTime; } +int LoopTimer::getCurrentTime() const { return SDL_GetTicks(); } + +void LoopTimer::advanceFixedUpdate() { elapsedFixedTime += fixedDeltaTime; } + +double LoopTimer::getFixedDeltaTime() const { return fixedDeltaTime; } + +void LoopTimer::setFPS(int FPS) { + this->FPS = FPS; + frameTargetTime = 1.0 / FPS; +} + +int LoopTimer::getFPS() const { return FPS; } + +void LoopTimer::enforceFrameRate() { + uint64_t currentFrameTime = SDL_GetTicks64(); + double frameDuration = (currentFrameTime - lastFrameTime) / 1000.0; + + if (frameDuration < frameTargetTime) { + uint32_t delayTime = (uint32_t) ((frameTargetTime - frameDuration) * 1000.0); + SDL_Delay(delayTime); + } +} +double LoopTimer::getLag() const { return elapsedTime - elapsedFixedTime; } diff --git a/mwe/events/src/uiObject.cpp b/mwe/events/src/uiObject.cpp new file mode 100644 index 0000000..947d1a2 --- /dev/null +++ b/mwe/events/src/uiObject.cpp @@ -0,0 +1,31 @@ +#include "uiObject.h" + +// Constructor for UIObject +UIObject::UIObject(int width, int height) : width(width), height(height) {} + +// Constructor for Button +Button::Button(int width, int height) : UIObject(width, height) {} + +Text::Text(int width, int height) + : UIObject(width, height), + size(12), + font(nullptr), + color{255, 255, 255} { // Default size and color + alignment.horizontal = Alignment::Horizontal::CENTER; + alignment.vertical = Alignment::Vertical::MIDDLE; + alignment.mode = Alignment::PositioningMode::RELATIVE; +} + +TextInput::TextInput(int width, int height) + : UIObject(width, height), + textBuffer(""), + placeholder(""), + isActive(false), + textColor{255, 255, 255}, + backgroundColor{0, 0, 0}, + maxLength(100), + font(nullptr) { + alignment.horizontal = Alignment::Horizontal::LEFT; + alignment.vertical = Alignment::Vertical::TOP; + alignment.mode = Alignment::PositioningMode::RELATIVE; +} diff --git a/mwe/events/src/uiRenderer.cpp b/mwe/events/src/uiRenderer.cpp new file mode 100644 index 0000000..ca8d284 --- /dev/null +++ b/mwe/events/src/uiRenderer.cpp @@ -0,0 +1,104 @@ +#include "uiRenderer.h" + +// Constructor +UIRenderer::UIRenderer(SDL_Renderer * renderer) : renderer(renderer) {} + +// Render function +void UIRenderer::render(UIObject * uiObject) { + if (Button * button = dynamic_cast<Button *>(uiObject)) { + renderButton(button); + } else if (Text * text = dynamic_cast<Text *>(uiObject)) { + renderText(text); + } else if (TextInput * textInput = dynamic_cast<TextInput *>(uiObject)) { + renderTextInput(textInput); + } +} + +// Private helper function to render a Button +void UIRenderer::renderButton(Button * button) { + SDL_Rect buttonRect = {button->x, button->y, button->width, button->height}; + SDL_SetRenderDrawColor(renderer, 100, 100, 255, 255); // Button color + SDL_RenderFillRect(renderer, &buttonRect); +} + +// Private helper function to render a Text +void UIRenderer::renderText(Text * text) { + if (text->font != nullptr) { + SDL_Color sdlColor = {text->color.red, text->color.green, text->color.blue, 255}; + SDL_Surface * textSurface + = TTF_RenderText_Blended(text->font, text->text.c_str(), sdlColor); + if (!textSurface) { + std::cerr << "Error creating text surface: " << TTF_GetError() << std::endl; + return; + } + + SDL_Texture * textTexture = SDL_CreateTextureFromSurface(renderer, textSurface); + if (!textTexture) { + std::cerr << "Error creating texture from surface: " << SDL_GetError() + << std::endl; + SDL_FreeSurface(textSurface); + return; + } + + SDL_Rect textRect = {text->x, text->y, textSurface->w, textSurface->h}; + SDL_RenderCopy(renderer, textTexture, nullptr, &textRect); + SDL_FreeSurface(textSurface); + SDL_DestroyTexture(textTexture); + } +} + +void UIRenderer::renderTextInput(TextInput * textInput) { + // // Check if textInput or renderer is null to avoid segmentation faults + // if (!textInput || !renderer) { + // std::cerr << "Error: Null pointer detected for textInput or renderer." << std::endl; + // return; + // } + + // // Render the background rectangle for the text input + // SDL_Rect inputRect = {textInput->x, textInput->y, textInput->width, textInput->height}; + // SDL_SetRenderDrawColor(renderer, textInput->backgroundColor.red, textInput->backgroundColor.green, textInput->backgroundColor.blue, 255); + // SDL_RenderFillRect(renderer, &inputRect); + + // // Check if font is valid + // if (!textInput->font) { + // std::cerr << "Error: Font is not loaded for textInput." << std::endl; + // return; + // } + + // SDL_Color sdlColor = {textInput->textColor.red, textInput->textColor.green, textInput->textColor.blue, 255}; + + // if (!textInput->textBuffer.empty()) { + // // Render the text in the input field + // SDL_Surface* textSurface = TTF_RenderText_Blended(textInput->font, textInput->textBuffer.c_str(), sdlColor); + // if (textSurface) { + // SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface); + // if (textTexture) { + // SDL_Rect textRect = {textInput->x + 5, textInput->y + 5, textSurface->w, textSurface->h}; + // SDL_RenderCopy(renderer, textTexture, nullptr, &textRect); + // SDL_DestroyTexture(textTexture); + // } else { + // std::cerr << "Error: Unable to create texture from text surface." << std::endl; + // } + // SDL_FreeSurface(textSurface); + // } else { + // std::cerr << "Error: Unable to create text surface." << std::endl; + // } + // } else if (!textInput->placeholder.empty()) { + // // Render the placeholder text + // SDL_Color placeholderColor = {128, 128, 128, 255}; // Light gray for placeholder + // SDL_Surface* placeholderSurface = TTF_RenderText_Blended(textInput->font, textInput->placeholder.c_str(), placeholderColor); + // if (placeholderSurface) { + // SDL_Texture* placeholderTexture = SDL_CreateTextureFromSurface(renderer, placeholderSurface); + // if (placeholderTexture) { + // SDL_Rect placeholderRect = {textInput->x + 5, textInput->y + 5, placeholderSurface->w, placeholderSurface->h}; + // SDL_RenderCopy(renderer, placeholderTexture, nullptr, &placeholderRect); + // SDL_DestroyTexture(placeholderTexture); + // } else { + // std::cerr << "Error: Unable to create texture from placeholder surface." << std::endl; + // } + // SDL_FreeSurface(placeholderSurface); + // } else { + // std::cerr << "Error: Unable to create placeholder surface." << std::endl; + // } + // } +} diff --git a/mwe/events/src/window.cpp b/mwe/events/src/window.cpp new file mode 100644 index 0000000..af2b627 --- /dev/null +++ b/mwe/events/src/window.cpp @@ -0,0 +1,45 @@ +#include "window.h" +#include <iostream> + +WindowManager::WindowManager() { this->uiRenderer = nullptr; } + +WindowManager::~WindowManager() { destroyWindow(); } + +bool WindowManager::initWindow() { + if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { + std::cerr << "Error initializing SDL.\n"; + return false; + } + + window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); + if (!window) { + std::cerr << "Error creating SDL Window.\n"; + return false; + } + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (!renderer) { + std::cerr << "Error creating SDL renderer.\n"; + return false; + } + + uiRenderer = new UIRenderer(renderer); + return true; +} + +void WindowManager::destroyWindow() { + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); +} + +SDL_Renderer * WindowManager::getRenderer() { return renderer; } +void WindowManager::addUIObject(UIObject * uiObject) { uiObjects.push_back(uiObject); } + +void WindowManager::renderUIObjects() { + for (UIObject * obj : uiObjects) { + uiRenderer->render(obj); + } + SDL_RenderPresent(this->renderer); +} diff --git a/mwe/events/versions/delayBased.cpp b/mwe/events/versions/delayBased.cpp new file mode 100644 index 0000000..634de9c --- /dev/null +++ b/mwe/events/versions/delayBased.cpp @@ -0,0 +1,55 @@ +#include "loopManager.h" +#include "timer.h" +LoopManager::LoopManager() {} +void LoopManager::processInput() { + SDL_Event event; + SDL_PollEvent(&event); + switch (event.type) { + case SDL_QUIT: + gameRunning = false; + break; + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_ESCAPE) { + gameRunning = false; + } + break; + } +} +void LoopManager::loop() { + fprintf(stderr, "loop. \n"); + while (gameRunning) { + //Timer::getInstance().update(); + //deltaTime = Timer::getInstance().getDeltaTime(); + processInput(); + update(); + render(); + } + window.destroyWindow(); +} +void LoopManager::setup() { + gameRunning = window.initWindow(); + LoopTimer::getInstance().start(); + LoopTimer::getInstance().setFPS(210); + + for (int i = 0; i < 2; i++) { + GameObject * square2 = new GameObject("square2", i * 40, i * 40, 20, 20, 0, 0); + objectList.push_back(square2); + } +} +void LoopManager::render() { + if (gameRunning) { + window.render(objectList); + } +} + +void LoopManager::update() { + LoopTimer & timer = LoopTimer::getInstance(); + timer.enforceFrameRate(); + timer.update(); + float delta = timer.getDeltaTime(); + + for (int i = 0; i < objectList.size(); i++) { + objectList[i]->setX(objectList[i]->getX() + 50 * delta); + objectList[i]->setY(objectList[i]->getY() + 50 * delta); + } +} |