187 lines
5.8 KiB
C++
187 lines
5.8 KiB
C++
//
|
|
// Created by trotfunky on 09/06/19.
|
|
//
|
|
|
|
#include "Rule.h"
|
|
|
|
|
|
Rule::Rule(std::shared_ptr<Entity> entity, State targetState, EntityType targetType,
|
|
const std::vector<std::shared_ptr<Entity>>& entities,
|
|
const std::vector<pro_maat::GridPos>& occupiedSquares, const pro_maat::GridPos& mapSize)
|
|
: entity(std::move(entity)),
|
|
targetState(targetState),
|
|
targetType(targetType),
|
|
entities(entities),
|
|
occupiedSquares(occupiedSquares),
|
|
mapSize(mapSize)
|
|
{}
|
|
|
|
void Rule::update()
|
|
{
|
|
if (targetState == State::Moving || targetState == State::Fleeing)
|
|
{
|
|
pro_maat::GridPos target = findTarget();
|
|
if(target != entity->getPosition())
|
|
{
|
|
entity->nextTarget = target;
|
|
entity->nextState = targetState;
|
|
}
|
|
else
|
|
{
|
|
entity->nextState = State::Idle;
|
|
}
|
|
|
|
entity->update();
|
|
}
|
|
else if (targetState == State::Waiting)
|
|
{
|
|
entity->nextTarget = entity->getPosition();
|
|
entity->nextState = State::Waiting;
|
|
entity->update();
|
|
}
|
|
else
|
|
{
|
|
entity->nextTarget = entity->getPosition();
|
|
entity->nextState = State::Idle;
|
|
entity->update();
|
|
}
|
|
}
|
|
|
|
pro_maat::GridPos Rule::findTarget()
|
|
{
|
|
std::vector<std::shared_ptr<Entity>> sortedEntities{};
|
|
sortedEntities.insert(sortedEntities.end(),entities.begin(),entities.end());
|
|
|
|
// Compares entities via their distance to the current entity
|
|
auto distanceSortEntities = [this](const std::shared_ptr<Entity>& leftHandSide, const std::shared_ptr<Entity>& rightHandSide){
|
|
return (pro_maat::manhattanDistance(entity->getPosition(),leftHandSide->getPosition()) <
|
|
pro_maat::manhattanDistance(entity->getPosition(),rightHandSide->getPosition()));
|
|
};
|
|
|
|
// Same but with grid coordinates
|
|
auto distanceSortSquares = [this](const pro_maat::GridPos& leftHandSide, const pro_maat::GridPos& rightHandSide){
|
|
return (pro_maat::manhattanDistance(entity->getPosition(),leftHandSide) <
|
|
pro_maat::manhattanDistance(entity->getPosition(),rightHandSide));
|
|
};
|
|
|
|
// Get the smallest, non-occupied, inside the map square
|
|
auto bestTarget = [this](const pro_maat::GridPos& leftHandSide, const pro_maat::GridPos& rightHandSide){
|
|
// If the left hand side operand is not in the map or occupied, it is not valid
|
|
if(!pro_maat::isInMap(leftHandSide,mapSize))
|
|
{
|
|
return(false);
|
|
}
|
|
else if(std::find(occupiedSquares.begin(),occupiedSquares.end(),leftHandSide) != occupiedSquares.end())
|
|
{
|
|
return(false);
|
|
}
|
|
else if(!pro_maat::isInMap(rightHandSide,mapSize))
|
|
{
|
|
return(true);
|
|
}
|
|
else if(std::find(occupiedSquares.begin(),occupiedSquares.end(),rightHandSide) != occupiedSquares.end())
|
|
{
|
|
return(true);
|
|
}
|
|
else
|
|
{
|
|
return(pro_maat::manhattanDistance(entity->getPosition(),leftHandSide) <
|
|
pro_maat::manhattanDistance(entity->getPosition(),rightHandSide));
|
|
}};
|
|
|
|
|
|
// Sort in order to minimize entities to process
|
|
std::sort(sortedEntities.begin(),sortedEntities.end(),distanceSortEntities);
|
|
|
|
for(const auto& processingEntity : sortedEntities)
|
|
{
|
|
if(processingEntity->getType() != targetType || processingEntity->getPosition() == entity->getPosition()) continue;
|
|
|
|
std::vector<pro_maat::GridPos> potentialTargets{};
|
|
|
|
pro_maat::GridUnit entityWidth = processingEntity->shape.getSize().x/pro_maat::pixelsPerUnit;
|
|
pro_maat::GridUnit entityHeight = processingEntity->shape.getSize().y/pro_maat::pixelsPerUnit;
|
|
|
|
potentialTargets.reserve((entityWidth+2)*2+entityHeight*2);
|
|
|
|
// Computes the top left corner just outside of the entity
|
|
pro_maat::GridPos topLeftCorner = processingEntity->getPosition();
|
|
topLeftCorner.first -= std::floor(entityWidth*0.5) + 1;
|
|
topLeftCorner.second -= std::floor(entityHeight*0.5) + 1;
|
|
|
|
|
|
// Get all the top and bottom adjacent squares
|
|
for(int i = 0;i<entityWidth+2;i++)
|
|
{
|
|
potentialTargets.emplace_back(topLeftCorner.first+i,topLeftCorner.second);
|
|
potentialTargets.emplace_back(topLeftCorner.first+i,topLeftCorner.second+entityHeight+1);
|
|
}
|
|
// Get the missing adjacent squares from the sides
|
|
for(int i = 1;i<=entityHeight;i++)
|
|
{
|
|
potentialTargets.emplace_back(topLeftCorner.first,topLeftCorner.second+i);
|
|
potentialTargets.emplace_back(topLeftCorner.first+entityWidth+1,topLeftCorner.second+i);
|
|
}
|
|
|
|
|
|
std::sort(potentialTargets.begin(),potentialTargets.end(),distanceSortSquares);
|
|
|
|
// If we are adjacent to a target, we do not need to move
|
|
if(std::find(potentialTargets.begin(),potentialTargets.end(),entity->getPosition()) != potentialTargets.end())
|
|
{
|
|
break;
|
|
}
|
|
|
|
auto target = std::min_element(potentialTargets.begin(),potentialTargets.end(),bestTarget);
|
|
|
|
if(target != potentialTargets.end())
|
|
{
|
|
return (*target);
|
|
}
|
|
}
|
|
|
|
return (entity->getPosition());
|
|
}
|
|
|
|
|
|
////////////////////////
|
|
// //
|
|
// Delegate overrides //
|
|
// //
|
|
////////////////////////
|
|
|
|
|
|
void Rule::move(Orientation orientation)
|
|
{
|
|
entity->move(orientation);
|
|
}
|
|
|
|
State Rule::getState() const
|
|
{
|
|
return entity->getState();
|
|
}
|
|
|
|
EntityType Rule::getType() const
|
|
{
|
|
return entity->getType();
|
|
}
|
|
|
|
const sf::RectangleShape& Rule::getShape() const
|
|
{
|
|
return entity->getShape();
|
|
}
|
|
|
|
pro_maat::GridPos Rule::getTarget() const
|
|
{
|
|
return entity->getTarget();
|
|
}
|
|
|
|
const pro_maat::GridPos Rule::getPosition() const
|
|
{
|
|
return entity->getPosition();
|
|
}
|
|
|
|
const std::vector<pro_maat::GridPos> Rule::getOccupiedSquares() const
|
|
{
|
|
return entity->getOccupiedSquares();
|
|
}
|