mirror of
https://github.com/Nimac0/SDL_Minigame
synced 2026-01-12 07:53:43 +00:00
InteractionManager + proof of concept
This commit is contained in:
parent
a9e754dd4f
commit
adaed679af
141
include/Entity.h
141
include/Entity.h
@ -35,85 +35,90 @@ class Entity
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* \brief Used for rendering order (last is highest) or retrieving entities of group
|
||||
* \todo Label used in singular entity shouldn't use plural
|
||||
* \todo HEARTS are rendered above POWERUPS, missleading order
|
||||
* \todo PROJECTILE are rendered above POWERUPS, missleading order
|
||||
* \todo Generalize HEARTS as UI or similar
|
||||
*/
|
||||
enum class GroupLabel
|
||||
{
|
||||
MAPTILES, //!< Entity using TileComponent
|
||||
PLAYERS, //!< Primary entity in player controll
|
||||
ENEMIES, //!< \deprecated All players now grouped as Entity::PLAYERS
|
||||
COLLIDERS, //!< Fixed collider entity, e.g. a wall
|
||||
PROJECTILE, //!< \todo Document
|
||||
HEARTS, //!< \todo Document
|
||||
POWERUPS //!< \todo Document
|
||||
};
|
||||
/*!
|
||||
* \brief Used for rendering order (last is highest) or retrieving entities of group
|
||||
* \todo Label used in singular entity shouldn't use plural
|
||||
* \todo HEARTS are rendered above POWERUPS, missleading order
|
||||
* \todo PROJECTILE are rendered above POWERUPS, missleading order
|
||||
* \todo Generalize HEARTS as UI or similar
|
||||
*/
|
||||
enum class GroupLabel
|
||||
{
|
||||
MAPTILES, //!< Entity using TileComponent
|
||||
PLAYERS, //!< Primary entity in player controll
|
||||
ENEMIES, //!< \deprecated All players now grouped as Entity::PLAYERS
|
||||
COLLIDERS, //!< Fixed collider entity, e.g. a wall
|
||||
PROJECTILE, //!< \todo Document
|
||||
HEARTS, //!< \todo Document
|
||||
POWERUPS //!< \todo Document
|
||||
};
|
||||
|
||||
/*!
|
||||
* \todo Document
|
||||
*/
|
||||
explicit Entity(Manager& mManager) :
|
||||
manager(mManager) { };
|
||||
/*!
|
||||
* \todo Document
|
||||
*/
|
||||
explicit Entity(Manager& mManager) :
|
||||
manager(mManager) { };
|
||||
|
||||
void update(uint_fast16_t diffTime) const; //!< Call each frame to update all components
|
||||
void update(uint_fast16_t diffTime) const; //!< Call each frame to update all components
|
||||
|
||||
bool isActive() const { return this->active; } //!< \sa destroy()
|
||||
//! Mark for destruction for Manager::refresh() and disables collision
|
||||
//! \sa ColliderComponent
|
||||
void destroy() {
|
||||
this->active = false;
|
||||
if (this->hasComponent<ColliderComponent>()) {
|
||||
this->getComponent<ColliderComponent>().removeCollision();
|
||||
}
|
||||
}
|
||||
bool isActive() const { return this->active; } //!< \sa destroy()
|
||||
//! Mark for destruction for Manager::refresh() and disables collision
|
||||
//! \sa ColliderComponent
|
||||
void destroy() {
|
||||
this->active = false;
|
||||
if (this->hasComponent<ColliderComponent>()) {
|
||||
this->getComponent<ColliderComponent>().removeCollision();
|
||||
}
|
||||
}
|
||||
|
||||
bool hasGroup(Group mGroup); //!< \sa GroupLabel
|
||||
void addGroup(Group mGroup); //!< \sa GroupLabel
|
||||
void delGroup(Group mGroup); //!< \sa GroupLabel
|
||||
//! \returns bitset with true on position GroupLabel if the entity belongs to group
|
||||
//! \sa GroupLabel
|
||||
std::bitset<MAX_GROUPS> getGroupBitSet();
|
||||
bool hasGroup(Group mGroup); //!< \sa GroupLabel
|
||||
void addGroup(Group mGroup); //!< \sa GroupLabel
|
||||
void delGroup(Group mGroup); //!< \sa GroupLabel
|
||||
//! \returns bitset with true on position GroupLabel if the entity belongs to group
|
||||
//! \sa GroupLabel
|
||||
std::bitset<MAX_GROUPS> getGroupBitSet();
|
||||
|
||||
//! \sa Manager
|
||||
Manager& getManager() { return manager; };
|
||||
//! \sa Manager
|
||||
Manager& getManager() { return manager; };
|
||||
|
||||
template <typename T> bool hasComponent() const //! \sa Component
|
||||
{
|
||||
return componentBitSet[getComponentTypeID<T>()];
|
||||
}
|
||||
template <typename T> bool hasComponent() const //! \sa Component
|
||||
{
|
||||
return componentBitSet[getComponentTypeID<T>()];
|
||||
}
|
||||
|
||||
//! \brief Adds specified type as component and calls Component::init()
|
||||
//! \param mArgs Constructor arguments of component
|
||||
template <typename T, typename...TArgs> T& addComponent(TArgs&&...mArgs)
|
||||
{
|
||||
T* c(new T(std::forward<TArgs>(mArgs)...));
|
||||
c->entity = this;
|
||||
std::unique_ptr<Component> uPtr{ c };
|
||||
this->components.emplace_back(std::move(uPtr));
|
||||
//! \brief Adds specified type as component and calls Component::init()
|
||||
//! \param mArgs Constructor arguments of component
|
||||
template <typename T, typename...TArgs> T& addComponent(TArgs&&...mArgs)
|
||||
{
|
||||
T* c(new T(std::forward<TArgs>(mArgs)...));
|
||||
c->entity = this;
|
||||
std::shared_ptr<Component> uPtr{ c };
|
||||
this->components.at(getComponentTypeID<T>()) = std::move(uPtr);
|
||||
|
||||
componentArray[getComponentTypeID<T>()] = c;
|
||||
componentBitSet[getComponentTypeID<T>()] = true;
|
||||
componentArray[getComponentTypeID<T>()] = c;
|
||||
componentBitSet[getComponentTypeID<T>()] = true;
|
||||
|
||||
c->init();
|
||||
return *c;
|
||||
};
|
||||
c->init();
|
||||
return *c;
|
||||
};
|
||||
|
||||
template <typename T> T& getComponent() const //!< \todo: rewrite to use optionals
|
||||
{
|
||||
auto ptr(componentArray[getComponentTypeID<T>()]);
|
||||
return *static_cast<T*>(ptr);
|
||||
}
|
||||
template <typename T> T& getComponent() const //!< \todo: rewrite to use optionals
|
||||
{
|
||||
auto ptr(componentArray[getComponentTypeID<T>()]);
|
||||
return *static_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
template <typename T> std::shared_ptr<T> getComponentAsPointer() const
|
||||
{
|
||||
return std::static_pointer_cast<T>(components.at(getComponentTypeID<T>()));
|
||||
}
|
||||
|
||||
private:
|
||||
Manager& manager;
|
||||
bool active = true;
|
||||
std::vector<std::unique_ptr<Component>> components;
|
||||
Manager& manager;
|
||||
bool active = true;
|
||||
std::array<std::shared_ptr<Component>, MAX_COMPONENTS> components;
|
||||
|
||||
ComponentArray componentArray = {};
|
||||
ComponentBitSet componentBitSet;
|
||||
GroupBitSet groupBitSet;
|
||||
ComponentArray componentArray = {};
|
||||
ComponentBitSet componentBitSet;
|
||||
GroupBitSet groupBitSet;
|
||||
};
|
||||
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <SDL3/SDL_events.h>
|
||||
|
||||
class EventListener {
|
||||
public:
|
||||
virtual SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event) = 0;
|
||||
EventListener() {};
|
||||
virtual ~EventListener() {};
|
||||
};
|
||||
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "EventListener.h"
|
||||
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@ -9,10 +8,14 @@
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_init.h"
|
||||
|
||||
typedef std::function<SDL_AppResult(SDL_EventType, SDL_Event* const)> EventListener;
|
||||
|
||||
class EventManager {
|
||||
public:
|
||||
void registerListener(EventListener* listener, std::initializer_list<SDL_EventType> eventTypes);
|
||||
EventManager();
|
||||
|
||||
void registerListener(EventListener listener, std::initializer_list<Uint32> eventTypes);
|
||||
SDL_AppResult handleEvent(SDL_Event* const event);
|
||||
private:
|
||||
std::map<SDL_EventType, std::vector<EventListener*>> eventListeners = std::map<SDL_EventType, std::vector<EventListener*>>();
|
||||
std::map<Uint32, std::vector<EventListener>> eventListeners = std::map<Uint32, std::vector<EventListener>>();
|
||||
};
|
||||
@ -8,6 +8,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "EventManager.h"
|
||||
#include "InteractionManager.h"
|
||||
#include "Manager.h"
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_init.h"
|
||||
@ -49,10 +50,11 @@ public:
|
||||
/* static */ TextureManager* textureManager;
|
||||
/* static */ SoundManager* soundManager;
|
||||
/* static */ InputManager* inputManager;
|
||||
RenderManager* renderManager;
|
||||
EventManager* eventManager;
|
||||
InteractionManager* interactionManager;
|
||||
|
||||
Manager manager;
|
||||
RenderManager renderManager;
|
||||
EventManager eventManager;
|
||||
Map* map; // game specific, might not be needed for all types of games
|
||||
|
||||
ConfigLoader* config;
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "EventListener.h"
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_init.h"
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <SDL3/SDL.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
@ -10,7 +9,7 @@
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
class InputManager : public EventListener {
|
||||
class InputManager {
|
||||
public:
|
||||
enum class EventType {
|
||||
KeyDown,
|
||||
@ -121,6 +120,8 @@ public:
|
||||
std::vector<Key> getBindings(const std::string& actionName, const std::string& context) const;
|
||||
std::vector<InputAction*> getActionsByKey(const Key key) const;
|
||||
|
||||
SDL_AppResult handleEvent(SDL_EventType type, SDL_Event* const event);
|
||||
|
||||
private:
|
||||
// TODO: flesh this out to avoid loops in process actions
|
||||
// additionally to actionsByContext, not instead
|
||||
@ -131,7 +132,6 @@ private:
|
||||
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);
|
||||
|
||||
15
include/InteractionEventdataStruct.h
Normal file
15
include/InteractionEventdataStruct.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Entity.h"
|
||||
#include "InteractionListener.h"
|
||||
#include "Vector2D.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
struct InteractionEventdataStruct {
|
||||
void* actor; // suggestion, can also be used for other arbitrary data
|
||||
void* data;
|
||||
std::weak_ptr<InteractionListener> target = std::weak_ptr<InteractionListener>();
|
||||
std::shared_ptr<Vector2D> targetingReference; // required without explicit target
|
||||
uint8_t strategy = 0; // required without explicit target, defaults to none
|
||||
};
|
||||
17
include/InteractionListener.h
Normal file
17
include/InteractionListener.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "Vector2D.h"
|
||||
#include <memory>
|
||||
|
||||
class InteractionListener {
|
||||
public:
|
||||
InteractionListener() { };
|
||||
virtual ~InteractionListener() { };
|
||||
|
||||
virtual void interact(void* actor, void* data) = 0;
|
||||
virtual std::shared_ptr<Vector2D> getPosition() // required for targeting strategy, return null to only allow explicit targeting
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
35
include/InteractionManager.h
Normal file
35
include/InteractionManager.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "InteractionListener.h"
|
||||
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_init.h"
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <ranges>
|
||||
|
||||
// TODO: ranges concept to avoid to<vector> in cpp
|
||||
typedef std::function<std::shared_ptr<InteractionListener>(Vector2D*, std::vector<std::shared_ptr<InteractionListener>>)> TargetingFunc;
|
||||
|
||||
class InteractionManager {
|
||||
public:
|
||||
InteractionManager();
|
||||
InteractionManager (const InteractionManager&) = delete;
|
||||
InteractionManager& operator= (const InteractionManager&) = delete;
|
||||
|
||||
enum class TargetingStrategy : uint8_t {
|
||||
none = 0,
|
||||
closest,
|
||||
manhattenDistance
|
||||
};
|
||||
|
||||
SDL_AppResult handleInteract(SDL_EventType type, SDL_Event* const event);
|
||||
void registerListener(std::weak_ptr<InteractionListener> listener);
|
||||
uint8_t registerTargetingFunc(TargetingFunc func);
|
||||
private:
|
||||
|
||||
std::vector<std::weak_ptr<InteractionListener>> listeners;
|
||||
std::array<TargetingFunc, 256> targetingFuncs;
|
||||
};
|
||||
@ -2,19 +2,24 @@
|
||||
|
||||
#include <functional>
|
||||
#include "Component.h"
|
||||
#include "InteractionListener.h"
|
||||
|
||||
class PowerupComponent : public Component
|
||||
class PowerupComponent : public Component, public InteractionListener
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Powerup Component object
|
||||
* @param func The function to be called when the powerup is picked up
|
||||
*/
|
||||
PowerupComponent(std::function<void (Entity*)> func);
|
||||
~PowerupComponent() {};
|
||||
/**
|
||||
* @brief Construct a new Powerup Component object
|
||||
* @param func The function to be called when the powerup is picked up
|
||||
*/
|
||||
PowerupComponent(std::function<void (Entity*)> func);
|
||||
~PowerupComponent() {};
|
||||
|
||||
void update(uint_fast16_t diffTime) override;
|
||||
void update(uint_fast16_t diffTime) override;
|
||||
|
||||
|
||||
void interact(void* actor, void* data) override;
|
||||
std::shared_ptr<Vector2D> getPosition() override;
|
||||
|
||||
private:
|
||||
std::function<void (Entity*)> pickupFunc;
|
||||
std::function<void (Entity*)> pickupFunc;
|
||||
};
|
||||
@ -7,7 +7,7 @@ class RenderObject
|
||||
public:
|
||||
virtual void draw() = 0;
|
||||
|
||||
RenderObject(int zIndex, RenderManager& renderManager);
|
||||
RenderObject(int zIndex, RenderManager* renderManager);
|
||||
~RenderObject();
|
||||
|
||||
int getZIndex() { return this->zIndex; };
|
||||
@ -23,5 +23,5 @@ private:
|
||||
int zIndex = 0;
|
||||
|
||||
protected:
|
||||
RenderManager& renderManager;
|
||||
RenderManager* renderManager;
|
||||
};
|
||||
@ -40,6 +40,11 @@ private:
|
||||
const char* path; //!< empty string if texture has a texture enum value, otherwise the path of the texture
|
||||
|
||||
public:
|
||||
//debug
|
||||
Textures getTexture() { return this->textureEnum; }
|
||||
|
||||
|
||||
|
||||
SpriteComponent(Textures texture, int zIndex);
|
||||
SpriteComponent(Textures texture, int xOffset, int yOffset, int zIndex);
|
||||
SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex);
|
||||
|
||||
@ -83,9 +83,15 @@ class TextureManager
|
||||
*/
|
||||
SDL_Texture* loadMapTileTexture(const char* path);
|
||||
|
||||
std::string getTexturePath(Textures texture) {
|
||||
return this->texture_references.at(texture);
|
||||
}
|
||||
|
||||
private:
|
||||
SDL_ScaleMode scaleMode = SDL_SCALEMODE_NEAREST;
|
||||
Manager* manager;
|
||||
std::map<Textures, SDL_Texture*> texture_cache;
|
||||
std::map<std::string, SDL_Texture*> mapTile_texture_cache;
|
||||
|
||||
std::map<Textures, std::string> texture_references;
|
||||
};
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
enum VEGO_Event {
|
||||
VEGO_Event_Interaction = SDL_EVENT_USER
|
||||
};
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
|
||||
namespace vego {
|
||||
extern Uint32 VEGO_Event_Interaction;
|
||||
}
|
||||
@ -37,6 +37,8 @@ void AssetManager::createPowerup(Vector2D pos, std::function<void (Entity*)> pic
|
||||
powerups.addComponent<ColliderComponent>("powerup", 0.6f);
|
||||
powerups.addComponent<PowerupComponent>(pickupFunc);
|
||||
powerups.addGroup((size_t)Entity::GroupLabel::POWERUPS);
|
||||
|
||||
VEGO_Game().interactionManager->registerListener(powerups.getComponentAsPointer<PowerupComponent>());
|
||||
}
|
||||
|
||||
Vector2D AssetManager::calculateSpawnPosition()
|
||||
|
||||
@ -6,7 +6,9 @@
|
||||
|
||||
void Entity::update(uint_fast16_t diffTime) const
|
||||
{
|
||||
for (auto const& c : components) c->update(diffTime);
|
||||
for (auto const& c : components)
|
||||
if (c)
|
||||
c->update(diffTime);
|
||||
}
|
||||
|
||||
bool Entity::hasGroup(Group mGroup)
|
||||
|
||||
@ -1,16 +1,27 @@
|
||||
#include "EventManager.h"
|
||||
#include "EventListener.h"
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_init.h"
|
||||
#include "SDL3/SDL_stdinc.h"
|
||||
#include "VEGO_Event.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
void EventManager::registerListener(EventListener* listener, std::initializer_list<SDL_EventType> eventTypes)
|
||||
Uint32 vego::VEGO_Event_Interaction;
|
||||
|
||||
EventManager::EventManager()
|
||||
{
|
||||
std::ranges::for_each(eventTypes.begin(), eventTypes.end(), [this, &listener](const SDL_EventType& eventType) {
|
||||
|
||||
/// \TODO: from c++26 you (should be able to) can get the amount of name values in an enum
|
||||
vego::VEGO_Event_Interaction = SDL_RegisterEvents(1); // TODO: error handling
|
||||
}
|
||||
|
||||
void EventManager::registerListener(EventListener listener, std::initializer_list<Uint32> eventTypes)
|
||||
{
|
||||
std::ranges::for_each(eventTypes.begin(), eventTypes.end(), [this, &listener](const Uint32& eventType) {
|
||||
if (!this->eventListeners.contains(eventType)) {
|
||||
this->eventListeners.insert({eventType, std::vector<EventListener*>()});
|
||||
this->eventListeners.insert({eventType, std::vector<EventListener>()});
|
||||
}
|
||||
this->eventListeners.at(eventType).emplace_back(listener);
|
||||
});
|
||||
@ -21,8 +32,8 @@ SDL_AppResult EventManager::handleEvent(SDL_Event* event)
|
||||
SDL_EventType type = (SDL_EventType) event->type;
|
||||
if (this->eventListeners.contains(type)) {
|
||||
auto results = this->eventListeners.at(type) | std::views::transform(
|
||||
[&event](EventListener* listener) {
|
||||
return listener->handleEvent((SDL_EventType) event->type, event);
|
||||
[&event](EventListener listener) {
|
||||
return listener((SDL_EventType) event->type, event);
|
||||
});
|
||||
if (std::ranges::contains(results, SDL_APP_FAILURE))
|
||||
return SDL_APP_FAILURE;
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
|
||||
#include "CollisionHandler.h"
|
||||
#include "AssetManager.h"
|
||||
#include "EventManager.h"
|
||||
#include "InputManager.h"
|
||||
#include "InteractionManager.h"
|
||||
#include "RenderManager.h"
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
#include "SDL3/SDL_events.h"
|
||||
@ -17,12 +20,12 @@
|
||||
|
||||
#include <VEGO.h>
|
||||
#include <VEGO_Event.h>
|
||||
#include <functional>
|
||||
|
||||
#include "ConfigLoader.h"
|
||||
|
||||
GameInternal::GameInternal() :
|
||||
manager(this),
|
||||
renderManager(),
|
||||
tiles(manager.getGroup((size_t)Entity::GroupLabel::MAPTILES)),
|
||||
players(manager.getGroup((size_t)Entity::GroupLabel::PLAYERS)),
|
||||
projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE)),
|
||||
@ -48,10 +51,12 @@ SDL_AppResult GameInternal::init()
|
||||
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 });
|
||||
GameInternal::renderManager = new RenderManager();
|
||||
GameInternal::eventManager = new EventManager();
|
||||
GameInternal::interactionManager = new InteractionManager();
|
||||
|
||||
/// \TODO: from c++26 you (should be able to) can loop through all values of an enum
|
||||
SDL_RegisterEvents(VEGO_Event_Interaction);
|
||||
this->eventManager->registerListener(std::bind_front(&InputManager::handleEvent, this->inputManager), { SDL_EVENT_KEY_DOWN, SDL_EVENT_KEY_UP });
|
||||
this->eventManager->registerListener(std::bind_front(&InteractionManager::handleInteract, VEGO_Game().interactionManager), { vego::VEGO_Event_Interaction });
|
||||
|
||||
int flags = 0;
|
||||
if (finalConfig.at("fullscreen"))
|
||||
@ -122,7 +127,7 @@ SDL_AppResult GameInternal::init()
|
||||
}
|
||||
|
||||
SDL_AppResult GameInternal::handleEvent(SDL_Event* event) {
|
||||
SDL_AppResult result = this->eventManager.handleEvent(event);
|
||||
SDL_AppResult result = this->eventManager->handleEvent(event);
|
||||
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
this->clean();
|
||||
@ -147,7 +152,7 @@ void GameInternal::update(Uint64 frameTime)
|
||||
void GameInternal::render()
|
||||
{
|
||||
SDL_RenderClear(renderer);
|
||||
this->renderManager.renderAll();
|
||||
this->renderManager->renderAll();
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
#include "InputManager.h"
|
||||
#include "InteractionEventdataStruct.h"
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_init.h"
|
||||
#include <iostream>
|
||||
#include "SDL3/SDL_stdinc.h"
|
||||
#include "VEGO.h"
|
||||
#include "VEGO_Event.h"
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, InputManager::Key key) {
|
||||
static const std::unordered_map<InputManager::Key, std::string> keyToString {
|
||||
@ -342,14 +346,11 @@ std::string InputManager::getActiveContext() const {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
90
src/InteractionManager.cpp
Normal file
90
src/InteractionManager.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include "InteractionManager.h"
|
||||
|
||||
#include "InteractionEventdataStruct.h"
|
||||
#include "InteractionListener.h"
|
||||
#include "SDL3/SDL_init.h"
|
||||
#include "VEGO_Event.h"
|
||||
#include "Vector2D.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
InteractionManager::InteractionManager()
|
||||
{
|
||||
this->targetingFuncs.fill(nullptr);
|
||||
this->targetingFuncs.at(static_cast<std::underlying_type<InteractionManager::TargetingStrategy>::type>(InteractionManager::TargetingStrategy::closest)) = [](Vector2D* reference, std::vector<std::shared_ptr<InteractionListener>> input) {
|
||||
return std::shared_ptr<InteractionListener>();
|
||||
};
|
||||
this->targetingFuncs.at(static_cast<std::underlying_type<InteractionManager::TargetingStrategy>::type>(InteractionManager::TargetingStrategy::closest)) = [](Vector2D* reference, std::vector<std::shared_ptr<InteractionListener>> input) {
|
||||
auto min = std::ranges::min_element(input, [&reference](std::shared_ptr<InteractionListener>& a, std::shared_ptr<InteractionListener>& b) {
|
||||
std::shared_ptr<Vector2D> coordA = a->getPosition();
|
||||
std::shared_ptr<Vector2D> coordB = b->getPosition();
|
||||
|
||||
if (coordB == nullptr) return true;
|
||||
if (coordA == nullptr) return false;
|
||||
|
||||
return std::sqrt(std::pow(coordA->x - reference->x, 2) + std::pow(coordA->y - reference->y, 2)) < std::sqrt(std::pow(coordB->x - reference->x, 2) + std::pow(coordB->y - reference->y, 2));
|
||||
});
|
||||
return min == std::ranges::end(input) ? nullptr : *min;
|
||||
};
|
||||
this->targetingFuncs.at(static_cast<std::underlying_type<InteractionManager::TargetingStrategy>::type>(InteractionManager::TargetingStrategy::manhattenDistance)) = [](Vector2D* reference, std::vector<std::shared_ptr<InteractionListener>> input) {
|
||||
auto min = std::ranges::min_element(input, [&reference](std::shared_ptr<InteractionListener>& a, std::shared_ptr<InteractionListener>& b) {
|
||||
std::shared_ptr<Vector2D> coordA = a->getPosition();
|
||||
std::shared_ptr<Vector2D> coordB = b->getPosition();
|
||||
|
||||
if (coordB == nullptr) return true;
|
||||
if (coordA == nullptr) return false;
|
||||
|
||||
return (std::abs(coordA->x - reference->x) + std::abs(coordA->y - reference->y)) < (std::abs(coordB->x - reference->x) + std::abs(coordB->y - reference->y));
|
||||
});
|
||||
return min == std::ranges::end(input) ? nullptr : *min;
|
||||
};
|
||||
}
|
||||
|
||||
SDL_AppResult InteractionManager::handleInteract(SDL_EventType type, SDL_Event* const event)
|
||||
{
|
||||
if (type != vego::VEGO_Event_Interaction) { // error handling
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
InteractionEventdataStruct* data = static_cast<InteractionEventdataStruct*>(event->user.data1);
|
||||
|
||||
std::shared_ptr<InteractionListener> listener = data->target.lock();
|
||||
|
||||
if (data->strategy != static_cast<std::underlying_type<InteractionManager::TargetingStrategy>::type>(InteractionManager::TargetingStrategy::none)) {
|
||||
listener = this->targetingFuncs.at(data->strategy)(
|
||||
data->targetingReference.get(),
|
||||
this->listeners
|
||||
| std::views::transform(&std::weak_ptr<InteractionListener>::lock)
|
||||
| std::views::filter(&std::shared_ptr<InteractionListener>::operator bool)
|
||||
| std::ranges::to<std::vector>()
|
||||
);
|
||||
}
|
||||
|
||||
if (listener) {
|
||||
listener->interact(data->actor, data->data);
|
||||
}
|
||||
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
void InteractionManager::registerListener(std::weak_ptr<InteractionListener> listener)
|
||||
{
|
||||
this->listeners.emplace_back(listener);
|
||||
}
|
||||
|
||||
uint8_t InteractionManager::registerTargetingFunc(TargetingFunc func)
|
||||
{
|
||||
auto it = std::ranges::find_if(this->targetingFuncs, [](const auto& func) {
|
||||
return !func;
|
||||
});
|
||||
(*it) = func;
|
||||
return std::distance(this->targetingFuncs.begin(), it);
|
||||
}
|
||||
@ -3,9 +3,13 @@
|
||||
#include "CollisionHandler.h"
|
||||
#include "Entity.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "SpriteComponent.h"
|
||||
#include "StatEffectsComponent.h"
|
||||
#include "Constants.h"
|
||||
#include "TextureManager.h"
|
||||
#include "TransformComponent.h"
|
||||
#include <cstdint>
|
||||
#include "VEGO.h"
|
||||
|
||||
PowerupComponent::PowerupComponent(std::function<void (Entity*)> func)
|
||||
{
|
||||
@ -24,3 +28,15 @@ void PowerupComponent::update(uint_fast16_t diffTime)
|
||||
this->entity->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PowerupComponent::interact(void* actor, void* data)
|
||||
{
|
||||
std::cout << VEGO_Game().textureManager->getTexturePath(this->entity->getComponent<SpriteComponent>().getTexture()) << std::endl;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<Vector2D> PowerupComponent::getPosition()
|
||||
{
|
||||
return std::make_shared<Vector2D>(this->entity->getComponent<TransformComponent>().position);
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
#include "RenderObject.h"
|
||||
#include "RenderManager.h"
|
||||
|
||||
RenderObject::RenderObject(int zIndex, RenderManager& renderManager) : zIndex(zIndex), renderManager(renderManager) {
|
||||
renderManager.add(this);
|
||||
RenderObject::RenderObject(int zIndex, RenderManager* renderManager) : zIndex(zIndex), renderManager(renderManager) {
|
||||
renderManager->add(this);
|
||||
}
|
||||
|
||||
RenderObject::~RenderObject() {
|
||||
this->renderManager.remove(this);
|
||||
this->renderManager->remove(this);
|
||||
}
|
||||
@ -18,7 +18,7 @@
|
||||
SpriteComponent::SpriteComponent(Textures texture, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(0), textureYOffset(0)
|
||||
{
|
||||
this->textureEnum = texture;
|
||||
this->path = "";
|
||||
this->path = "";
|
||||
}
|
||||
|
||||
SpriteComponent::SpriteComponent(Textures texture, int xOffset, int yOffset, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(xOffset), textureYOffset(yOffset)
|
||||
|
||||
@ -15,6 +15,9 @@ void TextureManager::addSingleTexture(Textures texture, const char* filePath) {
|
||||
|
||||
SDL_SetTextureScaleMode(sdlTexture, this->scaleMode); // linear scaling results in blurry images
|
||||
this->texture_cache.emplace(texture, sdlTexture);
|
||||
if (filePath != nullptr) {
|
||||
this->texture_references.emplace(texture, std::string(filePath));
|
||||
}
|
||||
std::cout << "Loaded texture at " << filePath << std::endl;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user