0
0
mirror of https://github.com/Nimac0/SDL_Minigame synced 2026-01-12 07:53:43 +00:00

rewrite interaction logic to be more concise

forgot to commit this the last time i worked on it
This commit is contained in:
ineslelin 2025-01-14 12:38:31 +01:00
parent a093fe3ccf
commit 7e0a2422bd
2 changed files with 61 additions and 185 deletions

View File

@ -14,25 +14,20 @@ public:
void init() override;
void update() override;
Entity* getClosestInteractableEntity(Direction direction, Entity* interactor, std::vector<Entity*> entities);
bool interact(Entity* interactor, Entity* interactee);
Entity* getClosestInteractableEntity(Direction direction, Entity* interactor, std::vector<Entity*> entities);
private:
bool canInteract;
bool isInteractable;
int reach;
Entity* findClosestEntityLeft(std::vector<Entity*>& entities, TransformComponent& interactorT);
Entity* findClosestEntityRight(std::vector<Entity*>& entities, TransformComponent& interactorT);
Entity* findClosestEntityUp(std::vector<Entity*>& entities, TransformComponent& interactorT);
Entity* findClosestEntityDown(std::vector<Entity*>& entities, TransformComponent& interactorT);
Entity* findClosestEntity(std::vector<Entity*>& entities, TransformComponent& interactorT, Direction direction);
std::function<bool(const TransformComponent&)> getDirectionalCheck(Direction direction, const TransformComponent& interactorT);
bool isEntityCloseEnough(const TransformComponent& interactorT, const TransformComponent& entityT, Direction direction);
float calculateDistance(Vector2D iPos, Vector2D ePos);
bool isEntityCloseEnoughRight(Vector2D iPos, Vector2D ePos, int iWidth);
bool isEntityCloseEnoughLeft(Vector2D iPos, Vector2D ePos, int eWidth);
bool isEntityCloseEnoughUp(Vector2D iPos, Vector2D ePos, int eHeight);
bool isEntityCloseEnoughDown(Vector2D iPos, Vector2D ePos, int iHeight);
};

View File

@ -4,226 +4,107 @@
#include <limits>
InteractionComponent::InteractionComponent(bool canInteract, bool isInteractable, int reach)
{
this->canInteract = canInteract;
this->isInteractable = isInteractable;
this->reach = reach; // ofc that can be set individually, but its probably also okay if you just pass your entities width as its reach here methinks
}
: canInteract(canInteract), isInteractable(isInteractable), reach(reach) {}
InteractionComponent::~InteractionComponent() = default;
void InteractionComponent::init()
{
void InteractionComponent::init() {}
}
void InteractionComponent::update()
{
}
Entity* InteractionComponent::getClosestInteractableEntity(Direction direction, Entity* interactor, std::vector<Entity*> entities)
{
// first kicking all the entities passed here that don't have the ability to be interacted with
for (auto it = entities.begin(); it != entities.end(); it++)
{
if (!(*it)->hasComponent<InteractionComponent>() || !(*it)->getComponent<InteractionComponent>().isInteractable)
{
it = entities.erase(it);
continue;
}
}
// quick check if entities isn't empty
if(entities.empty())
{
return nullptr;
}
// to reduce the amount of accesses to transformcomponent via getComponent()
auto& interactorT = interactor->getComponent<TransformComponent>();
// kick all entities that are either too far away or in the opposite direction, then calc distance and find closest entity that way
Entity* entityToInteract = nullptr;
switch(direction)
{
case Direction::LEFT: entityToInteract = findClosestEntityLeft(entities, interactorT);
break;
case Direction::RIGHT: entityToInteract = findClosestEntityRight(entities, interactorT);
break;
case Direction::UP: entityToInteract = findClosestEntityUp(entities, interactorT);
break;
case Direction::DOWN: entityToInteract = findClosestEntityDown(entities, interactorT);
break;
}
return entityToInteract;
}
void InteractionComponent::update() {}
bool InteractionComponent::interact(Entity* interactor, Entity* interactee)
{
if(!interactor->hasComponent<InteractionComponent>() || !interactor->getComponent<InteractionComponent>().canInteract)
{
throw std::logic_error("Interactor entity cannot interact");
}
if(!interactee->hasComponent<InteractionComponent>() || !interactee->getComponent<InteractionComponent>().isInteractable)
{
return false;
}
return true;
}
Entity* InteractionComponent::findClosestEntityLeft(std::vector<Entity*>& entities, TransformComponent& interactorT)
Entity* InteractionComponent::getClosestInteractableEntity(Direction direction, Entity* interactor, std::vector<Entity*> entities)
{
Entity* closestEntity = nullptr;
float closestDistance = std::numeric_limits<float>::max();
entities.erase(std::remove_if(entities.begin(), entities.end(), [](Entity* e) {
return !e->hasComponent<InteractionComponent>() || !e->getComponent<InteractionComponent>().isInteractable;
}), entities.end());
for(auto it = entities.begin(); it != entities.end(); it++)
{
auto& entityT = (*it)->getComponent<TransformComponent>();
if(entityT.position.x > interactorT.position.x || !isEntityCloseEnoughLeft(interactorT.position, entityT.position, entityT.width))
{
it = entities.erase(it);
continue;
}
if(entities.empty())
return nullptr;
float distance = calculateDistance(interactorT.position, entityT.position);
if (distance < closestDistance)
{
closestDistance = distance;
closestEntity = *it;
}
}
return closestEntity;
auto& interactorT = interactor->getComponent<TransformComponent>();
return findClosestEntity(entities, interactorT, direction);
}
Entity* InteractionComponent::findClosestEntityRight(std::vector<Entity*>& entities, TransformComponent& interactorT)
Entity* InteractionComponent::findClosestEntity(std::vector<Entity*>& entities, TransformComponent& interactorT, Direction direction)
{
Entity* closestEntity = nullptr;
float closestDistance = std::numeric_limits<float>::max();
for(auto it = entities.begin(); it != entities.end(); it++)
{
auto& entityT = (*it)->getComponent<TransformComponent>();
if(entityT.position.x < interactorT.position.x || !isEntityCloseEnoughRight(interactorT.position, entityT.position, interactorT.width))
{
it = entities.erase(it);
continue;
}
auto isInDirection = getDirectionalCheck(direction, interactorT);
entities.erase(std::remove_if(entities.begin(), entities.end(), [&](Entity* e){
auto& entityT = entity->getComponent<TransformComponent>();
return !isInDirection(entityT) || !isEntityCloseEnough(interactorT, entityT, direction);
}), entities.end());
for(auto e : entities)
{
auto& entityT = entity->getComponent<TransformComponent>();
float distance = calculateDistance(interactorT.position, entityT.position);
if (distance < closestDistance)
{
if (distance < closestDistance) {
closestDistance = distance;
closestEntity = *it;
closestEntity = entity;
}
}
return closestEntity;
}
Entity* InteractionComponent::findClosestEntityUp(std::vector<Entity*>& entities, TransformComponent& interactorT)
std::function<bool(const TransformComponent&)> InteractionComponent::getDirectionalCheck(Direction direction, const TransformComponent& interactorT)
{
Entity* closestEntity = nullptr;
float closestDistance = std::numeric_limits<float>::max();
for(auto it = entities.begin(); it != entities.end(); it++)
switch(direction)
{
auto& entityT = (*it)->getComponent<TransformComponent>();
if(entityT.position.y < interactorT.position.y || !isEntityCloseEnoughUp(interactorT.position, entityT.position, entityT.height))
{
it = entities.erase(it);
continue;
}
float distance = calculateDistance(interactorT.position, entityT.position);
if (distance < closestDistance)
{
closestDistance = distance;
closestEntity = *it;
}
case Direction::LEFT:
return[&interactorT](const TransformComponent& entityT) {
return entityT.position.x < interactorT.position.x;
};
case Direction::RIGHT:
return[&interactorT](const TransformComponent& entityT) {
return entityT.position.x > interactorT.position.x;
};
case Direction::UP:
return[&interactorT](const TransformComponent& entityT) {
return entityT.position.y < interactorT.position.y;
};
case Direction::DOWN:
return[&interactorT](const TransformComponent& entityT) {
return entityT.position.y > interactorT.position.y;
};
default:
return [](const TransformComponent&) { return false; };
}
return closestEntity;
}
Entity* InteractionComponent::findClosestEntityDown(std::vector<Entity*>& entities, TransformComponent& interactorT)
bool InteractionComponent::isEntityCloseEnough(const TransformComponent& interactorT, const TransformComponent& entityT, Direction direction)
{
Entity* closestEntity = nullptr;
float closestDistance = std::numeric_limits<float>::max();
for(auto it = entities.begin(); it != entities.end(); it++)
switch (direction)
{
auto& entityT = (*it)->getComponent<TransformComponent>();
if(entityT.position.y > interactorT.position.y || !isEntityCloseEnoughDown(interactorT.position, entityT.position, interactorT.height))
{
it = entities.erase(it);
continue;
}
float distance = calculateDistance(interactorT.position, entityT.position);
if (distance < closestDistance)
{
closestDistance = distance;
closestEntity = *it;
}
case Direction::LEFT:
return (entityT.position.x >= (interactorT.position.x - reach));
case Direction::RIGHT:
return (entityT.position.x <= (interactorT.position.x + reach));
case Direction::UP:
return (entityT.position.y >= (interactorT.position.y - reach));
case Direction::DOWN:
return (entityT.position.y <= (interactorT.position.y + reach));
default:
return false;
}
return closestEntity;
}
float InteractionComponent::calculateDistance(Vector2D iPos, Vector2D ePos)
{
return std::abs(ePos.x - iPos.x) + std::abs(ePos.y - iPos.y);
}
bool InteractionComponent::isEntityCloseEnoughRight(Vector2D iPos, Vector2D ePos, int iWidth)
{
if(ePos.x > ((int)iPos.x + (iWidth + reach)))
{
return false;
}
return true;
}
bool InteractionComponent::isEntityCloseEnoughLeft(Vector2D iPos, Vector2D ePos, int eWidth)
{
if(ePos.x < ((int)iPos.x - (reach - eWidth)))
{
return false;
}
return true;
}
bool InteractionComponent::isEntityCloseEnoughUp(Vector2D iPos, Vector2D ePos, int eHeight)
{
if(ePos.y < ((int)iPos.y - (reach - eHeight)))
{
return false;
}
return true;
}
bool InteractionComponent::isEntityCloseEnoughDown(Vector2D iPos, Vector2D ePos, int iHeight)
{
if(ePos.y > ((int)iPos.y + (iHeight + reach)))
{
return false;
}
return true;
}