diff options
26 files changed, 1224 insertions, 2 deletions
| diff --git a/.vscode/settings.json b/.vscode/settings.json index af4ae4e..936b057 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,67 @@  {  	"cmake.sourceDirectory": "${workspaceFolder}/src",  	"files.associations": { -		"*.tcc": "cpp" +		"functional": "cpp", +		"array": "cpp", +		"atomic": "cpp", +		"bit": "cpp", +		"*.tcc": "cpp", +		"cctype": "cpp", +		"charconv": "cpp", +		"chrono": "cpp", +		"clocale": "cpp", +		"cmath": "cpp", +		"compare": "cpp", +		"concepts": "cpp", +		"cstdarg": "cpp", +		"cstddef": "cpp", +		"cstdint": "cpp", +		"cstdio": "cpp", +		"cstdlib": "cpp", +		"cstring": "cpp", +		"ctime": "cpp", +		"cwchar": "cpp", +		"cwctype": "cpp", +		"deque": "cpp", +		"list": "cpp", +		"map": "cpp", +		"string": "cpp", +		"unordered_map": "cpp", +		"vector": "cpp", +		"exception": "cpp", +		"algorithm": "cpp", +		"iterator": "cpp", +		"memory": "cpp", +		"memory_resource": "cpp", +		"numeric": "cpp", +		"optional": "cpp", +		"random": "cpp", +		"ratio": "cpp", +		"string_view": "cpp", +		"system_error": "cpp", +		"tuple": "cpp", +		"type_traits": "cpp", +		"utility": "cpp", +		"format": "cpp", +		"initializer_list": "cpp", +		"iomanip": "cpp", +		"iosfwd": "cpp", +		"iostream": "cpp", +		"istream": "cpp", +		"limits": "cpp", +		"new": "cpp", +		"numbers": "cpp", +		"ostream": "cpp", +		"semaphore": "cpp", +		"span": "cpp", +		"sstream": "cpp", +		"stdexcept": "cpp", +		"stop_token": "cpp", +		"streambuf": "cpp", +		"thread": "cpp", +		"cinttypes": "cpp", +		"typeinfo": "cpp", +		"valarray": "cpp", +		"variant": "cpp"  	}  } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..05054c5 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ +    "tasks": [ +        { +            "type": "cppbuild", +            "label": "C/C++: g++ build active file", +            "command": "/usr/bin/g++", +            "args": [ +                "-fdiagnostics-color=always", +                "-g", +                "${file}", +                "-o", +                "${fileDirname}/${fileBasenameNoExtension}" +            ], +            "options": { +                "cwd": "${fileDirname}" +            }, +            "problemMatcher": [ +                "$gcc" +            ], +            "group": { +                "kind": "build", +                "isDefault": true +            }, +            "detail": "Task generated by Debugger." +        } +    ], +    "version": "2.0.0" +}
\ No newline at end of file diff --git a/mwe/.vscode/settings.json b/mwe/.vscode/settings.json new file mode 100644 index 0000000..c7913ab --- /dev/null +++ b/mwe/.vscode/settings.json @@ -0,0 +1,11 @@ +{ +    "files.associations": { +        "variant": "cpp", +        "*.tcc": "cpp", +        "string": "cpp", +        "unordered_map": "cpp", +        "string_view": "cpp", +        "ostream": "cpp", +        "iostream": "cpp" +    } +} diff --git a/mwe/events/.vscode/c_cpp_properties.json b/mwe/events/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..64d3f90 --- /dev/null +++ b/mwe/events/.vscode/c_cpp_properties.json @@ -0,0 +1,15 @@ +{ +    "configurations": [ +        { +            "name": "Linux", +            "includePath": [ +                "${workspaceFolder}/**" +            ], +            "defines": [], +            "cStandard": "c17", +            "cppStandard": "c++17", +            "intelliSenseMode": "linux-clang-x64" +        } +    ], +    "version": 4 +}
\ No newline at end of file diff --git a/mwe/events/.vscode/settings.json b/mwe/events/.vscode/settings.json new file mode 100644 index 0000000..816d790 --- /dev/null +++ b/mwe/events/.vscode/settings.json @@ -0,0 +1,68 @@ +{ +    "files.associations": { +        "iostream": "cpp", +        "array": "cpp", +        "atomic": "cpp", +        "bit": "cpp", +        "*.tcc": "cpp", +        "cctype": "cpp", +        "clocale": "cpp", +        "cmath": "cpp", +        "compare": "cpp", +        "concepts": "cpp", +        "cstdarg": "cpp", +        "cstddef": "cpp", +        "cstdint": "cpp", +        "cstdio": "cpp", +        "cstdlib": "cpp", +        "cwchar": "cpp", +        "cwctype": "cpp", +        "deque": "cpp", +        "list": "cpp", +        "map": "cpp", +        "string": "cpp", +        "unordered_map": "cpp", +        "vector": "cpp", +        "exception": "cpp", +        "algorithm": "cpp", +        "functional": "cpp", +        "iterator": "cpp", +        "memory": "cpp", +        "memory_resource": "cpp", +        "numeric": "cpp", +        "optional": "cpp", +        "random": "cpp", +        "string_view": "cpp", +        "system_error": "cpp", +        "tuple": "cpp", +        "type_traits": "cpp", +        "utility": "cpp", +        "initializer_list": "cpp", +        "iosfwd": "cpp", +        "istream": "cpp", +        "limits": "cpp", +        "new": "cpp", +        "numbers": "cpp", +        "ostream": "cpp", +        "sstream": "cpp", +        "stdexcept": "cpp", +        "streambuf": "cpp", +        "cinttypes": "cpp", +        "typeinfo": "cpp", +        "valarray": "cpp", +        "variant": "cpp", +        "condition_variable": "cpp", +        "ctime": "cpp", +        "forward_list": "cpp", +        "executor": "cpp", +        "io_context": "cpp", +        "netfwd": "cpp", +        "ratio": "cpp", +        "timer": "cpp", +        "future": "cpp", +        "mutex": "cpp", +        "semaphore": "cpp", +        "stop_token": "cpp", +        "thread": "cpp" +    } +} diff --git a/mwe/events/CMakeLists.txt b/mwe/events/CMakeLists.txt new file mode 100644 index 0000000..585d869 --- /dev/null +++ b/mwe/events/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.5) +project(gameloop) + +# Set the C++ standard (optional, but good practice) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) +set(CMAKE_BUILD_TYPE Debug) + +# Find the SDL2 package +find_package(SDL2 REQUIRED) + +add_executable(gameloop +	src/window.cpp +	src/main.cpp +	#src/eventHandler.cpp +	src/eventManager.cpp +	src/event.cpp +	src/loopManager.cpp +	src/timer.cpp +	src/keyCodes.cpp +	src/eventHandler.cpp +) + +# Link the SDL2 library to your project +target_link_libraries(gameloop ${SDL2_LIBRARIES}) + +# Include SDL2 header files and project headers +target_include_directories(gameloop PRIVATE ${SDL2_INCLUDE_DIRS}) +target_include_directories(gameloop PRIVATE ${CMAKE_SOURCE_DIR}/include) + diff --git a/mwe/events/imgs/demo.bmp b/mwe/events/imgs/demo.bmpBinary files differ new 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.jpgBinary files differ new file mode 100644 index 0000000..f534e1b --- /dev/null +++ b/mwe/events/imgs/demo.jpg diff --git a/mwe/events/include/event.h b/mwe/events/include/event.h new file mode 100644 index 0000000..802140c --- /dev/null +++ b/mwe/events/include/event.h @@ -0,0 +1,87 @@ +#pragma once +#include <cstdint> +#include <iostream> +#include <string> +#include <unordered_map> +#include <variant> +#include "keyCodes.h" + +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; +}; + +// 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; +}; diff --git a/mwe/events/include/eventHandler.h b/mwe/events/include/eventHandler.h new file mode 100644 index 0000000..e5b99d6 --- /dev/null +++ b/mwe/events/include/eventHandler.h @@ -0,0 +1,48 @@ +#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..709796a --- /dev/null +++ b/mwe/events/include/eventManager.h @@ -0,0 +1,57 @@ +#pragma once +#include <unordered_map> +#include <memory> +#include "event.h" +#include "keyCodes.h" +#include "eventHandler.h" +#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>> m_eventsQueue; +    std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>> m_subscribers; +    std::unordered_map<int, std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>> m_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/keyCodes.h b/mwe/events/include/keyCodes.h new file mode 100644 index 0000000..c3a7826 --- /dev/null +++ b/mwe/events/include/keyCodes.h @@ -0,0 +1,143 @@ +#pragma once +#include <cstdint> +#include <unordered_map> +#include <SDL2/SDL.h> +using Keycode = uint16_t; +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/loopManager.h b/mwe/events/include/loopManager.h new file mode 100644 index 0000000..5c519d9 --- /dev/null +++ b/mwe/events/include/loopManager.h @@ -0,0 +1,28 @@ +#pragma once +#include "window.h" +#include <SDL2/SDL.h> +#include "timer.h" +//#include "combinedEvent.h" +#include "eventManager.h" +#include "loopManager.h" +#include "eventHandler.h" +class LoopManager { +public: +	LoopManager(); +	void setup(); +	void loop(); +	void setRunning(bool running); +private: +	void processInput(); +	void update(); +	void lateUpdate(); +	void fixedUpdate(); +	void render(); +	bool gameRunning = false; +	WindowManager window; +	int timeScale = 1; +	float accumulator = 0.0; +	double currentTime; +	double t = 0.0; +	double dt = 0.01; +}; 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/window.h b/mwe/events/include/window.h new file mode 100644 index 0000000..9020b1a --- /dev/null +++ b/mwe/events/include/window.h @@ -0,0 +1,19 @@ +#pragma once +#include <SDL2/SDL.h> +#include <iostream> +#include <vector> +class WindowManager { +public: +	WindowManager(); +	virtual ~WindowManager(); +	bool initWindow(); +	void destroyWindow(); + +	SDL_Renderer * getRenderer(); + +private: +	const int SCREEN_WIDTH = 800; +	const int SCREEN_HEIGHT = 600; +	SDL_Window * window = NULL; +	SDL_Renderer * renderer = NULL; +}; diff --git a/mwe/events/src/event.cpp b/mwe/events/src/event.cpp new file mode 100644 index 0000000..fecae76 --- /dev/null +++ b/mwe/events/src/event.cpp @@ -0,0 +1,56 @@ +#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}; +} diff --git a/mwe/events/src/eventHandler.cpp b/mwe/events/src/eventHandler.cpp new file mode 100644 index 0000000..7040d8d --- /dev/null +++ b/mwe/events/src/eventHandler.cpp @@ -0,0 +1,5 @@ +#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..ce8e940 --- /dev/null +++ b/mwe/events/src/eventManager.cpp @@ -0,0 +1,109 @@ +#include "eventManager.h" + +void EventManager::shutdown() +{ +    m_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 = m_subscribersByEventId.find(eventType); + +        if (subscribers != m_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; +            } +        } +        m_subscribersByEventId[eventType][eventId].emplace_back(std::move(handler)); + +    } else { +        std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator subscribers = m_subscribers.find(eventType); +        if (subscribers != m_subscribers.end()) { +            std::vector<std::unique_ptr<IEventHandlerWrapper>>& handlers = subscribers->second; +            for (std::unique_ptr<IEventHandlerWrapper>& it : handlers) { +                if (it->getType() == handler->getType()) { +                    // log for double register +                    return; +                } +            } +            handlers.emplace_back(std::move(handler)); +        } else { +            m_subscribers[eventType].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 subscribers = m_subscribersByEventId.find(eventType); +        if (subscribers != m_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()) { +                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 = m_subscribers.find(eventType); +        if (handlersIt != m_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) +{ +    std::vector<std::unique_ptr<IEventHandlerWrapper>>& handlers = m_subscribers[event_.getEventType()]; +    for (std::unique_ptr<IEventHandlerWrapper>& handler : handlers) { +        handler->exec(event_); +    } + +    std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>& handlersMap = m_subscribersByEventId[event_.getEventType()]; +    std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator handlersIt = handlersMap.find(eventId); +    if (handlersIt != handlersMap.end()) { +        std::vector<std::unique_ptr<IEventHandlerWrapper>>& callbacks = handlersIt->second; +        for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it = callbacks.begin(); it != callbacks.end();) { +            std::unique_ptr<IEventHandlerWrapper>& handler = *it; +            handler->exec(event_); +            if (handler->isDestroyOnSuccess()) { +                it = callbacks.erase(it); +            } else { +                ++it; +            } +        } +    } +} + +void EventManager::queueEvent(std::unique_ptr<Event>&& event_, int eventId) +{ +    m_eventsQueue.emplace_back(std::move(event_), eventId); +} + +void EventManager::dispatchEvents() +{ +    for (std::vector<std::pair<std::unique_ptr<Event>, int>>::iterator eventIt = m_eventsQueue.begin(); eventIt != m_eventsQueue.end();) { +        if (!eventIt->first.get()->getHandled()) { +            triggerEvent(*eventIt->first.get(), eventIt->second); +            eventIt = m_eventsQueue.erase(eventIt); +        } else { +            ++eventIt; +        } +    } +} diff --git a/mwe/events/src/keyCodes.cpp b/mwe/events/src/keyCodes.cpp new file mode 100644 index 0000000..6f35d11 --- /dev/null +++ b/mwe/events/src/keyCodes.cpp @@ -0,0 +1,140 @@ +#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/loopManager.cpp b/mwe/events/src/loopManager.cpp new file mode 100644 index 0000000..6defda0 --- /dev/null +++ b/mwe/events/src/loopManager.cpp @@ -0,0 +1,90 @@ +#include "loopManager.h" + +LoopManager::LoopManager() {} +void LoopManager::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(); + +		while (timer.getLag() >= timer.getFixedDeltaTime()) { +			processInput(); +			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); + +} +void LoopManager::render() { +	//fprintf(stderr, "**********render********** \n"); +	if (gameRunning) { +		//window.render(objectList); +	} +} + +void LoopManager::update() { +	//fprintf(stderr, "**********normal update********** \n"); +	LoopTimer & timer = LoopTimer::getInstance(); + +	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); +	// } +} diff --git a/mwe/events/src/main.cpp b/mwe/events/src/main.cpp new file mode 100644 index 0000000..3940c60 --- /dev/null +++ b/mwe/events/src/main.cpp @@ -0,0 +1,50 @@ +#include <SDL2/SDL.h> +#include <iostream> +#include <memory> +#include "loopManager.h" +#include "event.h" + +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 onKeyPressed(const KeyPressedEvent& e) +{ +   const int keyCode = e.getKeyCode(); +	fprintf(stderr,"KeyCode %d\n",keyCode); +} +int main(int argc, char* args[]) { +	LoopManager gameLoop; +	// Create an event handler for KeyPressedEvent +    // EventHandler<KeyPressedEvent> callback = [](const KeyPressedEvent& e) { +    //     onKeyPressed(e); +    // }; +	// custom event class poc +	EventHandler<PlayerDamagedEvent> playerDamagedHandler = onPlayerDamaged; +	subscribe<PlayerDamagedEvent>(playerDamagedHandler); + +	triggerEvent(PlayerDamagedEvent(50, 1)); +	//EventHandler<KeyPressedEvent> callback = onKeyPressed; +    //subscribe<KeyPressedEvent>(callback,false); +	std::unique_ptr<Event> anotherKeyPressEvent = std::make_unique<KeyPressedEvent>(65); +    queueEvent(std::move(anotherKeyPressEvent)); +    triggerEvent(KeyPressedEvent(42)); +	EventManager::getInstance().dispatchEvents(); +	gameLoop.setup(); +	gameLoop.loop(); +    return 0; +} diff --git a/mwe/events/src/timer.cpp b/mwe/events/src/timer.cpp new file mode 100644 index 0000000..f4fee23 --- /dev/null +++ b/mwe/events/src/timer.cpp @@ -0,0 +1,54 @@ +#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/window.cpp b/mwe/events/src/window.cpp new file mode 100644 index 0000000..9cafd57 --- /dev/null +++ b/mwe/events/src/window.cpp @@ -0,0 +1,30 @@ +#include "window.h" +WindowManager::WindowManager() { +} +WindowManager::~WindowManager() { destroyWindow(); } +SDL_Renderer * WindowManager::getRenderer() { return renderer; } + +bool WindowManager::initWindow() { +	if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { +		fprintf(stderr, "Error inititalising SDL.\n"); +		return false; +	} +	window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, +							  SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, +							  SCREEN_HEIGHT, SDL_WINDOW_SHOWN); +	if (!window) { +		fprintf(stderr, "Error creating SDL Window. \n"); +		return false; +	} +	renderer = SDL_CreateRenderer(window, -1, 0); +	if (!renderer) { +		fprintf(stderr, "Error creating SDL renderer. \n"); +		return false; +	} +	return true; +} +void WindowManager::destroyWindow() { +	SDL_DestroyRenderer(renderer); +	SDL_DestroyWindow(window); +	SDL_Quit(); +} diff --git a/mwe/events/versions/delayBased.cpp b/mwe/events/versions/delayBased.cpp new file mode 100644 index 0000000..253a03a --- /dev/null +++ b/mwe/events/versions/delayBased.cpp @@ -0,0 +1,56 @@ +#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); +	} +} diff --git a/mwe/gameloop/include/eventManager.h b/mwe/gameloop/include/eventManager.h index 69c6801..ba1ca32 100644 --- a/mwe/gameloop/include/eventManager.h +++ b/mwe/gameloop/include/eventManager.h @@ -1 +1,5 @@ -class EventManager {}; +#pragma once +class EventManager { +	public: +		EventManager(); +}; diff --git a/mwe/gameloop/include/loopManager.h b/mwe/gameloop/include/loopManager.h index e202423..dcbfedc 100644 --- a/mwe/gameloop/include/loopManager.h +++ b/mwe/gameloop/include/loopManager.h @@ -2,6 +2,7 @@  #include "gameObject.h"  #include "window.h"  #include <SDL2/SDL.h> +#include "event.h"  class LoopManager {  public:  	LoopManager(); |