First implementation of rules

TODO :
 - Fix target as getter (currently broken because of inheritance by rules)
 - Smart pointers for entity store ?
This commit is contained in:
Teo-CD 2019-06-09 23:26:46 +02:00
parent febe0827ad
commit 08e922b0d4
12 changed files with 257 additions and 20 deletions

204
src/Rule.h Normal file
View file

@ -0,0 +1,204 @@
//
// Created by trotfunky on 09/06/19.
//
#ifndef PROJECT_MAAT_RULES_H
#define PROJECT_MAAT_RULES_H
#include <vector>
#include <algorithm>
#include "Entity.h"
/// Decorates entities with rules which will modify its behaviour
template <State targetState, EntityType targetType>
class Rule : public Entity
{
public:
Rule(Entity& entity, const std::vector<Entity>& entities,
const std::vector<pro_maat::GridPos>& occupiedSquares, const pro_maat::GridPos& mapSize);
void update() override;
void move(Orientation orientation) override;
State getState() const override;
const sf::RectangleShape& getShape() const override;
const pro_maat::GridPos getPosition() const override;
const std::vector<pro_maat::GridPos> getOccupiedSquares() const override;
private:
/// Finds the closest free square adjacent to the closest target entity type.
/// \return Suitable target square or current position if none was found.
pro_maat::GridPos findTarget();
Entity& entity;
const std::vector<Entity>& entities;
const std::vector<pro_maat::GridPos>& occupiedSquares;
const pro_maat::GridPos& mapSize;
};
template<State targetState, EntityType targetType>
Rule<targetState, targetType>::Rule(Entity& entity,
const std::vector<Entity>& entities,
const std::vector<pro_maat::GridPos>& occupiedSquares,
const pro_maat::GridPos& mapSize)
: entity(entity),
entities(entities),
occupiedSquares(occupiedSquares),
mapSize(mapSize)
{}
template<State targetState, EntityType targetType>
void Rule<targetState, targetType>::update()
{
if constexpr (targetState == State::Moving || targetState == State::Fleeing)
{
entity.nextTarget = findTarget();
if(entity.nextTarget == entity.getPosition())
{
entity.nextState = State::Idle;
}
else
{
entity.nextState = targetState;
}
entity.update();
}
else if constexpr (targetState == State::Waiting)
{
entity.nextTarget = entity.getPosition();
entity.nextState = State::Waiting;
entity.update();
}
else
{
entity.nextTarget = entity.getPosition();
entity.nextState = State::Idle;
entity.update();
}
}
template<State targetState, EntityType targetType>
pro_maat::GridPos Rule<targetState, targetType>::findTarget()
{
std::vector<Entity> sortedEntities{};
sortedEntities.insert(sortedEntities.end(),entities.begin(),entities.end());
// Compares entities via their distance to the current entity
auto distanceSortEntities = [this](const Entity& leftHandSide, const 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) ||
std::find(occupiedSquares.begin(),occupiedSquares.end(),leftHandSide) != occupiedSquares.end())
{
return(false);
}
else if(!pro_maat::isInMap(rightHandSide,mapSize) ||
std::find(occupiedSquares.begin(),occupiedSquares.end(),rightHandSide) != occupiedSquares.end())
{
return(true);
}
else
{
return(leftHandSide < rightHandSide);
}};
// Sort in order to minimize entities to process
std::sort(sortedEntities.begin(),sortedEntities.end(),distanceSortEntities);
for(const Entity& processingEntity : sortedEntities)
{
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 of the entity
pro_maat::GridPos topLeftCorner = processingEntity.getPosition();
topLeftCorner.first -= entityWidth*0.5 - 1;
topLeftCorner.second -= 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+2);
}
// 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+2,topLeftCorner.second+i);
}
std::sort(potentialTargets.begin(),potentialTargets.end(),distanceSortSquares);
auto target = std::min_element(potentialTargets.begin(),potentialTargets.end(),bestTarget);
if(target != potentialTargets.end())
{
return (*target);
}
}
return (entity.getPosition());
}
////////////////////////
// //
// Delegate overrides //
// //
////////////////////////
template<State targetState, EntityType targetType>
void Rule<targetState, targetType>::move(Orientation orientation)
{
entity.move(orientation);
}
template<State targetState, EntityType targetType>
State Rule<targetState, targetType>::getState() const
{
return entity.getState();
}
template<State targetState, EntityType targetType>
const sf::RectangleShape& Rule<targetState, targetType>::getShape() const
{
return entity.getShape();
}
template<State targetState, EntityType targetType>
const pro_maat::GridPos Rule<targetState, targetType>::getPosition() const
{
return entity.getPosition();
}
template<State targetState, EntityType targetType>
const std::vector<pro_maat::GridPos> Rule<targetState, targetType>::getOccupiedSquares() const
{
return entity.getOccupiedSquares();
}
#endif //PROJECT_MAAT_RULES_H