// // Created by trotfunky on 09/06/19. // #include "Rule.h" Rule::Rule(std::shared_ptr entity, State targetState, EntityType targetType, const std::vector>& entities, const std::vector& 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> 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& leftHandSide, const std::shared_ptr& 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 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;igetPosition()) != 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 Rule::getOccupiedSquares() const { return entity->getOccupiedSquares(); }