0
0
mirror of https://github.com/Nimac0/SDL_Minigame synced 2026-01-12 23:33:41 +00:00

Merge branch 'input2' into interactions-v2

This commit is contained in:
Benedikt Galbavy 2025-03-21 17:19:50 +01:00
parent d66d860cdc
commit a9e754dd4f
7 changed files with 647 additions and 123 deletions

View File

@ -5,7 +5,7 @@
class EventListener { class EventListener {
public: public:
virtual SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* event) = 0; virtual SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event) = 0;
EventListener() {}; EventListener() {};
virtual ~EventListener() {}; virtual ~EventListener() {};
}; };

View File

@ -12,7 +12,7 @@
class EventManager { class EventManager {
public: public:
void registerListener(EventListener* listener, std::initializer_list<SDL_EventType> eventTypes); void registerListener(EventListener* listener, std::initializer_list<SDL_EventType> eventTypes);
SDL_AppResult handleEvent(SDL_Event* event); SDL_AppResult handleEvent(SDL_Event* const event);
private: private:
std::map<SDL_EventType, std::vector<EventListener*>> eventListeners = std::map<SDL_EventType, std::vector<EventListener*>>(); std::map<SDL_EventType, std::vector<EventListener*>> eventListeners = std::map<SDL_EventType, std::vector<EventListener*>>();
}; };

View File

@ -13,6 +13,7 @@
#include "SDL3/SDL_init.h" #include "SDL3/SDL_init.h"
#include "Vector2D.h" #include "Vector2D.h"
#include "Entity.h" #include "Entity.h"
#include "InputManager.h"
#include "RenderManager.h" #include "RenderManager.h"
#include "ConfigLoader.h" #include "ConfigLoader.h"
@ -28,50 +29,50 @@ class Game;
class GameInternal class GameInternal
{ {
public: public:
GameInternal(); GameInternal();
~GameInternal(); ~GameInternal();
SDL_AppResult init(); SDL_AppResult init();
void handleEvents();
SDL_AppResult handleEvent(SDL_Event* event); SDL_AppResult handleEvent(SDL_Event* event);
void update(Uint64 frameTime); void update(Uint64 frameTime);
void render(); void render();
void clean(); void clean();
bool isRunning() const; bool isRunning() const;
void setRunning(bool running); // TODO: should be private/not accesible for game dev void setRunning(bool running); // TODO: should be private/not accesible for game dev
void stopGame(); void stopGame();
/* static */ SDL_Renderer* renderer = nullptr; /* static */ SDL_Renderer* renderer = nullptr;
/* static */ SDL_Event event; /* static */ SDL_Event event;
/* static */ CollisionHandler* collisionHandler; /* static */ CollisionHandler* collisionHandler;
/* static */ AssetManager* assets; /* static */ AssetManager* assets;
/* static */ TextureManager* textureManager; /* static */ TextureManager* textureManager;
/* static */ SoundManager* soundManager; /* static */ SoundManager* soundManager;
/* static */ InputManager* inputManager;
Manager manager; Manager manager;
RenderManager renderManager; RenderManager renderManager;
EventManager eventManager; EventManager eventManager;
Map* map; // game specific, might not be needed for all types of games Map* map; // game specific, might not be needed for all types of games
ConfigLoader* config; ConfigLoader* config;
std::vector<Entity*>& tiles; std::vector<Entity*>& tiles;
std::vector<Entity*>& players; std::vector<Entity*>& players;
std::vector<Entity*>& projectiles; std::vector<Entity*>& projectiles;
std::vector<Entity*>& hearts; std::vector<Entity*>& hearts;
std::vector<Entity*>& powerups; std::vector<Entity*>& powerups;
// end moved globals // end moved globals
void refreshPlayers(); void refreshPlayers();
private: private:
Game* gameInstance; Game* gameInstance;
int counter = 0; int counter = 0;
bool running = true; bool running = true;
SDL_Window* window; SDL_Window* window;
Uint64 lastFrameTime = 0; Uint64 lastFrameTime = 0;
}; };

141
include/InputManager.h Normal file
View File

@ -0,0 +1,141 @@
#pragma once
#include "EventListener.h"
#include "SDL3/SDL_events.h"
#include "SDL3/SDL_init.h"
#include <SDL3/SDL.h>
#include <map>
#include <string>
#include <functional>
#include <vector>
#include <iostream>
class InputManager : public EventListener {
public:
enum class EventType {
KeyDown,
KeyUp
};
enum class Key
{
UP,
DOWN,
LEFT,
RIGHT,
SPACE,
ENTER,
ESCAPE,
TAB,
BACKSPACE,
DELETE,
HOME,
END,
PAGE_UP,
PAGE_DOWN,
INSERT,
CAPS_LOCK,
LEFT_SHIFT,
RIGHT_SHIFT,
LEFT_CTRL,
RIGHT_CTRL,
LEFT_ALT,
RIGHT_ALT,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
NUM_0,
NUM_1,
NUM_2,
NUM_3,
NUM_4,
NUM_5,
NUM_6,
NUM_7,
NUM_8,
NUM_9,
LEFT_BRACKET,
RIGHT_BRACKET,
SEMICOLON,
APOSTROPHE,
COMMA,
PERIOD,
SLASH,
BACKSLASH,
GRAVE
};
struct InputAction {
std::string name;
std::vector<Key> bindings;
std::function<void()> callback;
};
InputManager();
~InputManager();
void init(); // see if necessary
void processEvents();
void registerAction(const std::string& actionName, const std::vector<Key>& keys, std::function<void()> callback, const std::string& context);
void setActiveContext(const std::string& context);
std::string getActiveContext() const;
void rebindAction(const std::string& actionName, const std::vector<Key>& newBindings, const std::string& context);
void removeBindings(const std::string& actionName, const std::string& context);
std::vector<Key> getBindings(const std::string& actionName, const std::string& context) const;
std::vector<InputAction*> getActionsByKey(const Key key) const;
private:
// TODO: flesh this out to avoid loops in process actions
// additionally to actionsByContext, not instead
std::map<std::string, std::vector<InputAction>> actionsByContext;
std::map<Key, std::vector<InputAction*>> actionsByKey;
std::map<Key, SDL_Scancode> keyMap;
std::string activeContext;
void initKeyMap();
SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event) override;
};
std::ostream& operator<<(std::ostream& os, InputManager::Key key);
std::ostream& operator<<(std::ostream& os, const InputManager::InputAction& action);
std::ostream& operator<<(std::ostream& os, const InputManager::InputAction* action);
std::ostream& operator<<(std::ostream& os, const std::vector<InputManager::InputAction>& actions);
std::ostream& operator<<(std::ostream& os, const std::vector<InputManager::InputAction*>& actions);

View File

@ -6,6 +6,7 @@
#include <SDL3_mixer/SDL_mixer.h> #include <SDL3_mixer/SDL_mixer.h>
#include "SDL3/SDL_events.h" #include "SDL3/SDL_events.h"
#include "SDL3/SDL_init.h" #include "SDL3/SDL_init.h"
#include "SDL3/SDL_oldnames.h"
#include "SoundManager.h" #include "SoundManager.h"
#include "Entity.h" #include "Entity.h"
#include "HealthComponent.h" #include "HealthComponent.h"
@ -20,161 +21,157 @@
#include "ConfigLoader.h" #include "ConfigLoader.h"
GameInternal::GameInternal() : GameInternal::GameInternal() :
manager(this), manager(this),
renderManager(), renderManager(),
tiles(manager.getGroup((size_t)Entity::GroupLabel::MAPTILES)), tiles(manager.getGroup((size_t)Entity::GroupLabel::MAPTILES)),
players(manager.getGroup((size_t)Entity::GroupLabel::PLAYERS)), players(manager.getGroup((size_t)Entity::GroupLabel::PLAYERS)),
projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE)), projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE)),
hearts(manager.getGroup((size_t)Entity::GroupLabel::HEARTS)), hearts(manager.getGroup((size_t)Entity::GroupLabel::HEARTS)),
powerups(manager.getGroup((size_t)Entity::GroupLabel::POWERUPS)) powerups(manager.getGroup((size_t)Entity::GroupLabel::POWERUPS))
{}; {};
GameInternal::~GameInternal() = default; GameInternal::~GameInternal() = default;
SDL_AppResult GameInternal::init() SDL_AppResult GameInternal::init()
{ {
config = new ConfigLoader(); config = new ConfigLoader();
this->gameInstance = GameFactory::instance().create(this); this->gameInstance = GameFactory::instance().create(this);
config->setCustomConfig(this->gameInstance->setConfigFilePath()); config->setCustomConfig(this->gameInstance->setConfigFilePath());
config->init(); config->init();
json finalConfig = config->getFinalConfig(); json finalConfig = config->getFinalConfig();
GameInternal::assets = new AssetManager(&manager); GameInternal::assets = new AssetManager(&manager);
GameInternal::textureManager = new TextureManager(&manager); GameInternal::textureManager = new TextureManager(&manager);
GameInternal::soundManager = new SoundManager(); GameInternal::soundManager = new SoundManager();
GameInternal::collisionHandler = new CollisionHandler(manager); // why does this use a referrence, but AssetManager a pointer? GameInternal::collisionHandler = new CollisionHandler(manager); // why does this use a referrence, but AssetManager a pointer?
GameInternal::inputManager = new InputManager();
this->eventManager.registerListener(inputManager, { SDL_EVENT_KEY_DOWN, SDL_EVENT_KEY_UP });
/// \TODO: from c++26 you (should be able to) can loop through all values of an enum /// \TODO: from c++26 you (should be able to) can loop through all values of an enum
SDL_RegisterEvents(VEGO_Event_Interaction); SDL_RegisterEvents(VEGO_Event_Interaction);
int flags = 0; int flags = 0;
if (finalConfig.at("fullscreen")) if (finalConfig.at("fullscreen"))
{ {
flags = SDL_WINDOW_FULLSCREEN; flags = SDL_WINDOW_FULLSCREEN;
} }
if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)) if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO))
{ {
std::cout << "ERROR. Subsystem couldnt be initialized! " << SDL_GetError() << std::endl; std::cout << "ERROR. Subsystem couldnt be initialized! " << SDL_GetError() << std::endl;
SDL_ClearError(); SDL_ClearError();
return SDL_APP_FAILURE; return SDL_APP_FAILURE;
} }
if (Mix_Init(MIX_INIT_MP3) != MIX_INIT_MP3) { if (Mix_Init(MIX_INIT_MP3) != MIX_INIT_MP3) {
std::cout << "ERROR. Subsystem couldnt be initialized!" << std::endl; std::cout << "ERROR. Subsystem couldnt be initialized!" << std::endl;
return SDL_APP_FAILURE; return SDL_APP_FAILURE;
} }
window = SDL_CreateWindow(finalConfig.at("title").get<std::string>().c_str(), window = SDL_CreateWindow(finalConfig.at("title").get<std::string>().c_str(),
finalConfig.at("screen_width"), finalConfig.at("screen_height"), flags); finalConfig.at("screen_width"), finalConfig.at("screen_height"), flags);
if (!window) if (!window)
{ {
std::cout << "ERROR: Window couldnt be created! " << SDL_GetError() << std::endl; std::cout << "ERROR: Window couldnt be created! " << SDL_GetError() << std::endl;
SDL_ClearError(); SDL_ClearError();
return SDL_APP_FAILURE; return SDL_APP_FAILURE;
} }
// bad // bad
SDL_Surface* icon; SDL_Surface* icon;
if((icon = SDL_LoadBMP(finalConfig.at("icon").get<std::string>().c_str()))) if((icon = SDL_LoadBMP(finalConfig.at("icon").get<std::string>().c_str())))
{ {
SDL_SetWindowIcon(window, icon); SDL_SetWindowIcon(window, icon);
} }
SDL_SetWindowIcon(window, icon); SDL_SetWindowIcon(window, icon);
renderer = SDL_CreateRenderer(window, NULL); renderer = SDL_CreateRenderer(window, NULL);
if (!renderer) if (!renderer)
{ {
std::cout << "ERROR: Renderer couldnt be created! " << SDL_GetError() << std::endl; std::cout << "ERROR: Renderer couldnt be created! " << SDL_GetError() << std::endl;
SDL_ClearError(); SDL_ClearError();
return SDL_APP_FAILURE; return SDL_APP_FAILURE;
} }
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
if (!Mix_OpenAudio(0, NULL)) if (!Mix_OpenAudio(0, NULL))
{ {
std::cout << "ERROR: Mixer couldnt be initialized! " << SDL_GetError() << std::endl; std::cout << "ERROR: Mixer couldnt be initialized! " << SDL_GetError() << std::endl;
SDL_ClearError(); SDL_ClearError();
return SDL_APP_FAILURE; return SDL_APP_FAILURE;
} }
Mix_Volume(-1, MIX_MAX_VOLUME); Mix_Volume(-1, MIX_MAX_VOLUME);
Mix_AllocateChannels(16); Mix_AllocateChannels(16);
// loading sounds // loading sounds
// assets->addSoundEffect("throw_egg", "assets/sound/throw_egg.wav"); // assets->addSoundEffect("throw_egg", "assets/sound/throw_egg.wav");
// assets->addSoundEffect("steps", "assets/sound/steps.wav"); // assets->addSoundEffect("steps", "assets/sound/steps.wav");
// loading music // loading music
// assets->addMusic("background_music", "assets/sound/background_music.mp3"); // assets->addMusic("background_music", "assets/sound/background_music.mp3");
this->gameInstance->init(); this->gameInstance->init();
return SDL_APP_CONTINUE; return SDL_APP_CONTINUE;
}
void GameInternal::handleEvents()
{
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_EVENT_QUIT: this->setRunning(false);
break;
default:
break;
}
} }
SDL_AppResult GameInternal::handleEvent(SDL_Event* event) { SDL_AppResult GameInternal::handleEvent(SDL_Event* event) {
return this->eventManager.handleEvent(event); SDL_AppResult result = this->eventManager.handleEvent(event);
if (event->type == SDL_EVENT_QUIT) {
this->clean();
return result == SDL_APP_FAILURE ? SDL_APP_FAILURE : SDL_APP_SUCCESS;
}
return result;
} }
void GameInternal::update(Uint64 frameTime) void GameInternal::update(Uint64 frameTime)
{ {
manager.refresh(); manager.refresh();
uint_fast16_t diffTime = frameTime - this->lastFrameTime; uint_fast16_t diffTime = frameTime - this->lastFrameTime;
manager.update(diffTime); manager.update(diffTime);
this->gameInstance->update(diffTime); // TODO: this might have to be split up into two update functions, before and after manager... this->gameInstance->update(diffTime); // TODO: this might have to be split up into two update functions, before and after manager...
this->lastFrameTime = frameTime; this->lastFrameTime = frameTime;
} }
void GameInternal::render() void GameInternal::render()
{ {
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
this->renderManager.renderAll(); this->renderManager.renderAll();
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }
void GameInternal::clean() void GameInternal::clean()
{ {
delete(textureManager); delete(textureManager);
SDL_DestroyRenderer(renderer); SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
SDL_Quit(); SDL_Quit();
std::cout << "Game Cleaned!" << std::endl; std::cout << "Game Cleaned!" << std::endl;
} }
bool GameInternal::isRunning() const bool GameInternal::isRunning() const
{ {
return running; return running;
} }
void GameInternal::setRunning(bool running) //TODO: might be depracted void GameInternal::setRunning(bool running) //TODO: might be depracted
{ {
this->running = running; this->running = running;
} }
void GameInternal::stopGame() void GameInternal::stopGame()
{ {
this->running = false; this->running = false;
} }

384
src/InputManager.cpp Normal file
View File

@ -0,0 +1,384 @@
#include "InputManager.h"
#include "SDL3/SDL_events.h"
#include "SDL3/SDL_init.h"
#include <iostream>
std::ostream& operator<<(std::ostream& os, InputManager::Key key) {
static const std::unordered_map<InputManager::Key, std::string> keyToString {
{InputManager::Key::UP, "UP"},
{InputManager::Key::DOWN, "DOWN"},
{InputManager::Key::LEFT, "LEFT"},
{InputManager::Key::RIGHT, "RIGHT"},
{InputManager::Key::SPACE, "SPACE"},
{InputManager::Key::ENTER, "ENTER"},
{InputManager::Key::ESCAPE, "ESCAPE"},
{InputManager::Key::TAB, "TAB"},
{InputManager::Key::BACKSPACE, "BACKSPACE"},
{InputManager::Key::DELETE, "DELETE"},
{InputManager::Key::HOME, "HOME"},
{InputManager::Key::END, "END"},
{InputManager::Key::PAGE_UP, "PAGE_UP"},
{InputManager::Key::PAGE_DOWN, "PAGE_DOWN"},
{InputManager::Key::INSERT, "INSERT"},
{InputManager::Key::CAPS_LOCK, "CAPS_LOCK"},
{InputManager::Key::LEFT_SHIFT, "LEFT_SHIFT"},
{InputManager::Key::RIGHT_SHIFT, "RIGHT_SHIFT"},
{InputManager::Key::LEFT_CTRL, "LEFT_CTRL"},
{InputManager::Key::RIGHT_CTRL, "RIGHT_CTRL"},
{InputManager::Key::LEFT_ALT, "LEFT_ALT"},
{InputManager::Key::RIGHT_ALT, "RIGHT_ALT"},
{InputManager::Key::F1, "F1"},
{InputManager::Key::F2, "F2"},
{InputManager::Key::F3, "F3"},
{InputManager::Key::F4, "F4"},
{InputManager::Key::F5, "F5"},
{InputManager::Key::F6, "F6"},
{InputManager::Key::F7, "F7"},
{InputManager::Key::F8, "F8"},
{InputManager::Key::F9, "F9"},
{InputManager::Key::F10, "F10"},
{InputManager::Key::F11, "F11"},
{InputManager::Key::F12, "F12"},
{InputManager::Key::A, "A"},
{InputManager::Key::B, "B"},
{InputManager::Key::C, "C"},
{InputManager::Key::D, "D"},
{InputManager::Key::E, "E"},
{InputManager::Key::F, "F"},
{InputManager::Key::G, "G"},
{InputManager::Key::H, "H"},
{InputManager::Key::I, "I"},
{InputManager::Key::J, "J"},
{InputManager::Key::K, "K"},
{InputManager::Key::L, "L"},
{InputManager::Key::M, "M"},
{InputManager::Key::N, "N"},
{InputManager::Key::O, "O"},
{InputManager::Key::P, "P"},
{InputManager::Key::Q, "Q"},
{InputManager::Key::R, "R"},
{InputManager::Key::S, "S"},
{InputManager::Key::T, "T"},
{InputManager::Key::U, "U"},
{InputManager::Key::V, "V"},
{InputManager::Key::W, "W"},
{InputManager::Key::X, "X"},
{InputManager::Key::Y, "Y"},
{InputManager::Key::Z, "Z"},
{InputManager::Key::NUM_0, "NUM_0"},
{InputManager::Key::NUM_1, "NUM_1"},
{InputManager::Key::NUM_2, "NUM_2"},
{InputManager::Key::NUM_3, "NUM_3"},
{InputManager::Key::NUM_4, "NUM_4"},
{InputManager::Key::NUM_5, "NUM_5"},
{InputManager::Key::NUM_6, "NUM_6"},
{InputManager::Key::NUM_7, "NUM_7"},
{InputManager::Key::NUM_8, "NUM_8"},
{InputManager::Key::NUM_9, "NUM_9"},
{InputManager::Key::LEFT_BRACKET, "LEFT_BRACKET"},
{InputManager::Key::RIGHT_BRACKET, "RIGHT_BRACKET"},
{InputManager::Key::SEMICOLON, "SEMICOLON"},
{InputManager::Key::APOSTROPHE, "APOSTROPHE"},
{InputManager::Key::COMMA, "COMMA"},
{InputManager::Key::PERIOD, "PERIOD"},
{InputManager::Key::SLASH, "SLASH"},
{InputManager::Key::BACKSLASH, "BACKSLASH"},
{InputManager::Key::GRAVE, "GRAVE"}
};
auto it = keyToString.find(key);
if (it != keyToString.end()) {
os << it->second;
} else {
os << "UNKNOWN_KEY";
}
return os;
}
std::ostream& operator<<(std::ostream& os, const InputManager::InputAction& action) {
os << action.name << " with binding(s): ";
for (size_t i = 0; i < action.bindings.size(); ++i) {
os << action.bindings[i];
if (i < action.bindings.size() - 1) {
os << ", ";
}
}
return os;
}
std::ostream& operator<<(std::ostream& os, const InputManager::InputAction* action) {
if (action) {
os << *action;
} else {
os << "NULL_ACTION";
}
return os;
}
std::ostream& operator<<(std::ostream& os, const std::vector<InputManager::InputAction>& actions) {
os << "Actions: ";
if (actions.empty()) {
os << "None";
} else {
for (size_t i = 0; i < actions.size(); ++i) {
os << actions[i];
if (i < actions.size() - 1) {
os << " | ";
}
}
}
return os;
}
// TODO: find out why it doesnt work??
std::ostream& operator<<(std::ostream& os, const std::vector<InputManager::InputAction*>& actions) {
os << "Actions: ";
if (actions.empty()) {
os << "None";
} else {
for (size_t i = 0; i < actions.size(); ++i) {
if (actions[i]) {
os << *actions[i];
} else {
os << "NULL_ACTION";
}
if (i < actions.size() - 1) {
os << " | ";
}
}
}
return os;
}
// overloads end --------------------------------------------------------------------------------------
InputManager::InputManager() : activeContext("Default") {}
InputManager::~InputManager() {}
void InputManager::init() {
if (SDL_Init(SDL_INIT_EVENTS) != 0) {
std::cerr << "Failed to initialize SDL: " << SDL_GetError() << std::endl;
return;
}
}
void InputManager::initKeyMap() {
keyMap = {
{Key::UP, SDL_SCANCODE_UP},
{Key::DOWN, SDL_SCANCODE_DOWN},
{Key::LEFT, SDL_SCANCODE_LEFT},
{Key::RIGHT, SDL_SCANCODE_RIGHT},
{Key::SPACE, SDL_SCANCODE_SPACE},
{Key::ENTER, SDL_SCANCODE_RETURN},
{Key::ESCAPE, SDL_SCANCODE_ESCAPE},
{Key::TAB, SDL_SCANCODE_TAB},
{Key::BACKSPACE, SDL_SCANCODE_BACKSPACE},
{Key::DELETE, SDL_SCANCODE_DELETE},
{Key::HOME, SDL_SCANCODE_HOME},
{Key::END, SDL_SCANCODE_END},
{Key::PAGE_UP, SDL_SCANCODE_PAGEUP},
{Key::PAGE_DOWN, SDL_SCANCODE_PAGEDOWN},
{Key::INSERT, SDL_SCANCODE_INSERT},
{Key::CAPS_LOCK, SDL_SCANCODE_CAPSLOCK},
{Key::LEFT_SHIFT, SDL_SCANCODE_LSHIFT},
{Key::RIGHT_SHIFT, SDL_SCANCODE_RSHIFT},
{Key::LEFT_CTRL, SDL_SCANCODE_LCTRL},
{Key::RIGHT_CTRL, SDL_SCANCODE_RCTRL},
{Key::LEFT_ALT, SDL_SCANCODE_LALT},
{Key::RIGHT_ALT, SDL_SCANCODE_RALT},
{Key::F1, SDL_SCANCODE_F1},
{Key::F2, SDL_SCANCODE_F2},
{Key::F3, SDL_SCANCODE_F3},
{Key::F4, SDL_SCANCODE_F4},
{Key::F5, SDL_SCANCODE_F5},
{Key::F6, SDL_SCANCODE_F6},
{Key::F7, SDL_SCANCODE_F7},
{Key::F8, SDL_SCANCODE_F8},
{Key::F9, SDL_SCANCODE_F9},
{Key::F10, SDL_SCANCODE_F10},
{Key::F11, SDL_SCANCODE_F11},
{Key::F12, SDL_SCANCODE_F12},
{Key::A, SDL_SCANCODE_A},
{Key::B, SDL_SCANCODE_B},
{Key::C, SDL_SCANCODE_C},
{Key::D, SDL_SCANCODE_D},
{Key::E, SDL_SCANCODE_E},
{Key::F, SDL_SCANCODE_F},
{Key::G, SDL_SCANCODE_G},
{Key::H, SDL_SCANCODE_H},
{Key::I, SDL_SCANCODE_I},
{Key::J, SDL_SCANCODE_J},
{Key::K, SDL_SCANCODE_K},
{Key::L, SDL_SCANCODE_L},
{Key::M, SDL_SCANCODE_M},
{Key::N, SDL_SCANCODE_N},
{Key::O, SDL_SCANCODE_O},
{Key::P, SDL_SCANCODE_P},
{Key::Q, SDL_SCANCODE_Q},
{Key::R, SDL_SCANCODE_R},
{Key::S, SDL_SCANCODE_S},
{Key::T, SDL_SCANCODE_T},
{Key::U, SDL_SCANCODE_U},
{Key::V, SDL_SCANCODE_V},
{Key::W, SDL_SCANCODE_W},
{Key::X, SDL_SCANCODE_X},
{Key::Y, SDL_SCANCODE_Y},
{Key::Z, SDL_SCANCODE_Z},
{Key::NUM_0, SDL_SCANCODE_0},
{Key::NUM_1, SDL_SCANCODE_1},
{Key::NUM_2, SDL_SCANCODE_2},
{Key::NUM_3, SDL_SCANCODE_3},
{Key::NUM_4, SDL_SCANCODE_4},
{Key::NUM_5, SDL_SCANCODE_5},
{Key::NUM_6, SDL_SCANCODE_6},
{Key::NUM_7, SDL_SCANCODE_7},
{Key::NUM_8, SDL_SCANCODE_8},
{Key::NUM_9, SDL_SCANCODE_9},
{Key::LEFT_BRACKET, SDL_SCANCODE_LEFTBRACKET},
{Key::RIGHT_BRACKET, SDL_SCANCODE_RIGHTBRACKET},
{Key::SEMICOLON, SDL_SCANCODE_SEMICOLON},
{Key::APOSTROPHE, SDL_SCANCODE_APOSTROPHE},
{Key::COMMA, SDL_SCANCODE_COMMA},
{Key::PERIOD, SDL_SCANCODE_PERIOD},
{Key::SLASH, SDL_SCANCODE_SLASH},
{Key::BACKSLASH, SDL_SCANCODE_BACKSLASH},
{Key::GRAVE, SDL_SCANCODE_GRAVE}
};
}
void InputManager::registerAction(const std::string& actionName, const std::vector<Key>& keys, std::function<void()> callback, const std::string& context) {
actionsByContext[context].emplace_back(actionName, keys, callback);
InputAction& storedAction = actionsByContext[context].back();
for (const auto& key : keys) {
actionsByKey[key].push_back(&storedAction);
}
std::cout << "Registered action: " << storedAction << " in context: " << context << std::endl;
}
void InputManager::rebindAction(const std::string& actionName, const std::vector<Key>& newBindings, const std::string& context) {
auto it = actionsByContext.find(context);
if (it != actionsByContext.end()) {
for (auto& action : it->second) {
if (action.name == actionName) {
for (const auto& key : action.bindings) {
auto& keyActions = actionsByKey[key];
keyActions.erase(std::remove(keyActions.begin(), keyActions.end(), &action), keyActions.end());
if (keyActions.empty()) {
actionsByKey.erase(key);
}
}
action.bindings = newBindings;
for (const auto& key : newBindings) {
actionsByKey[key].push_back(&action);
}
std::cout << "Rebound action: " << actionName << " in context: " << context << " to new bindings: ";
for (const auto& key : newBindings) {
std::cout << key << " ";
}
std::cout << std::endl;
return;
}
}
}
std::cout << "Action not found: " << actionName << " in context: " << context << std::endl;
}
void InputManager::removeBindings(const std::string& actionName, const std::string& context) {
auto it = actionsByContext.find(context);
if (it != actionsByContext.end()) {
for (auto& action : it->second) {
if (action.name == actionName) {
action.bindings.clear();
std::cout << "Removed bindings for action: " << actionName << " in context: " << context << std::endl;
return;
}
}
}
std::cout << "Action not found: " << actionName << " in context: " << context << std::endl;
}
std::vector<InputManager::Key> InputManager::getBindings(const std::string& actionName, const std::string& context) const {
auto it = actionsByContext.find(context);
if (it != actionsByContext.end()) {
for (const auto& action : it->second) {
if (action.name == actionName) {
return action.bindings;
}
}
}
std::cout << "Action not found: " << actionName << " in context: " << context << "\n";
return {};
}
std::vector<InputManager::InputAction*> InputManager::getActionsByKey(const Key key) const {
auto it = actionsByKey.find(key);
if (it != actionsByKey.end()) {
std::cout << "DEBUG: Found " << it->second.size() << " actions for key " << key << std::endl;
return it->second;
}
std::cout << "DEBUG: No actions found for key " << key << std::endl;
return {};
}
void InputManager::setActiveContext(const std::string& context) {
activeContext = context;
std::cout << "Active context set to: " << activeContext << std::endl;
}
std::string InputManager::getActiveContext() const {
return activeContext;
}
SDL_AppResult InputManager::handleEvent(SDL_EventType type, SDL_Event* const event) {
std::cout << "in handleEvent" << std::endl;
if (type != SDL_EVENT_KEY_DOWN) {
std::cout << "ignore key up" << std::endl;
return SDL_APP_CONTINUE;
}
if (event->key.repeat) {
std::cout << "ignore key repeat" << std::endl;
return SDL_APP_CONTINUE;
}
auto keyIt = std::ranges::find_if(keyMap,
[&](const auto& pair) { return pair.second == event->key.scancode; });
if (keyIt != keyMap.end()) {
std::cout << "in != keymap.end" << std::endl;
Key pressedKey = keyIt->first;
auto actionIt = actionsByKey.find(pressedKey);
if (actionIt != actionsByKey.end()) {
std::cout << "in != actionsByKey.end" << std::endl;
for (auto* action : actionIt->second) {
std::cout << "before if(action)" << std::endl;
if (action) {
std::cout << "after if(action)" << std::endl;
auto& activeActions = actionsByContext[activeContext];
if (std::ranges::find_if(activeActions,
[&](const InputAction& act) { return &act == action; }) != activeActions.end()) {
std::cout << "Action triggered: " << action->name << " in context: " << activeContext << std::endl;
action->callback();
}
}
}
}
}
return SDL_APP_CONTINUE;
}

View File

@ -27,7 +27,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) {
return SDL_APP_SUCCESS; return SDL_APP_SUCCESS;
} }
vego::game->handleEvents(); // bad //vego::game->handleEvents(); // bad
Uint64 frameStart = SDL_GetTicks(); Uint64 frameStart = SDL_GetTicks();
@ -39,6 +39,7 @@ SDL_AppResult SDL_AppIterate(void *appstate) {
return SDL_APP_CONTINUE; return SDL_APP_CONTINUE;
} }
// triggers upon every event
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
return vego::game->handleEvent(event); return vego::game->handleEvent(event);
} }