diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/behaviour_system.cpp | 55 | ||||
| -rw-r--r-- | src/direction.h | 4 | 
2 files changed, 39 insertions, 20 deletions
| diff --git a/src/behaviour_system.cpp b/src/behaviour_system.cpp index f4dc388..06e4ae0 100644 --- a/src/behaviour_system.cpp +++ b/src/behaviour_system.cpp | |||
| @@ -98,18 +98,19 @@ bool BehaviourSystem::isFollowingPath(int spriteId) { | |||
| 98 | } | 98 | } | 
| 99 | 99 | ||
| 100 | struct PathNodeInfo { | 100 | struct PathNodeInfo { | 
| 101 | int cheapestPathCost = INT_MAX; | 101 | double cheapestPathCost = DBL_MAX; | 
| 102 | int estimatedRemainingCost = INT_MAX; | 102 | double estimatedRemainingCost = DBL_MAX; | 
| 103 | vec2i previousPoint; | 103 | vec2i previousPoint; | 
| 104 | Direction dirFromPreviousPoint; | 104 | Direction dirFromPreviousPoint; | 
| 105 | }; | 105 | }; | 
| 106 | 106 | ||
| 107 | struct SearchNode { | 107 | struct SearchNode { | 
| 108 | vec2i point; | 108 | vec2i point; | 
| 109 | int estimatedCost = INT_MAX; | 109 | Direction dirFromPreviousPoint; | 
| 110 | double estimatedCost = DBL_MAX; | ||
| 110 | int tiebreaker; // this actually counts downward. wow | 111 | int tiebreaker; // this actually counts downward. wow | 
| 111 | 112 | ||
| 112 | SearchNode(vec2i point, int estimatedCost) : point(point), estimatedCost(estimatedCost) { | 113 | SearchNode(vec2i point, Direction dirFromPreviousPoint, double estimatedCost) : point(point), dirFromPreviousPoint(dirFromPreviousPoint), estimatedCost(estimatedCost) { | 
| 113 | static int tiebreakerCounter = 0; | 114 | static int tiebreakerCounter = 0; | 
| 114 | tiebreaker = tiebreakerCounter--; | 115 | tiebreaker = tiebreakerCounter--; | 
| 115 | } | 116 | } | 
| @@ -119,12 +120,14 @@ struct SearchNode { | |||
| 119 | } | 120 | } | 
| 120 | }; | 121 | }; | 
| 121 | 122 | ||
| 122 | int estimateRemainingCost(vec2i current, vec2i dest, int movementSpeed, bool cardinalDirectionsOnly) { | 123 | double estimateRemainingCost(vec2i current, vec2i dest, int movementSpeed, bool cardinalDirectionsOnly) { | 
| 123 | vec2i difference = dest - current; | 124 | vec2i difference = dest - current; | 
| 124 | if (cardinalDirectionsOnly) { | 125 | if (cardinalDirectionsOnly) { | 
| 125 | return (std::abs(difference.x()) + std::abs(difference.y())) / movementSpeed; | 126 | return (std::abs(difference.x()) + std::abs(difference.y())) / movementSpeed; | 
| 126 | } else { | 127 | } else { | 
| 127 | return std::max(std::abs(difference.x()), std::abs(difference.y())) / movementSpeed; | 128 | int dx = std::abs(difference.x()) / movementSpeed; | 
| 129 | int dy = std::abs(difference.y()) / movementSpeed; | ||
| 130 | return (dx + dy) + (1.4 - 2) * std::min(dx, dy); | ||
| 128 | } | 131 | } | 
| 129 | } | 132 | } | 
| 130 | 133 | ||
| @@ -146,13 +149,13 @@ void BehaviourSystem::createPath(int spriteId) { | |||
| 146 | } | 149 | } | 
| 147 | } | 150 | } | 
| 148 | 151 | ||
| 149 | int initialCostGuess = estimateRemainingCost(sprite.loc, sprite.pathfindingDestination, sprite.movementSpeed, sprite.cardinalDirectionsOnly); | 152 | double initialCostGuess = estimateRemainingCost(sprite.loc, sprite.pathfindingDestination, sprite.movementSpeed, sprite.cardinalDirectionsOnly); | 
| 150 | 153 | ||
| 151 | std::map<vec2i, PathNodeInfo> pathNodes; | 154 | std::map<vec2i, std::map<Direction, PathNodeInfo>> pathNodes; | 
| 152 | pathNodes[sprite.loc] = PathNodeInfo{.cheapestPathCost = 0, .estimatedRemainingCost = initialCostGuess}; | 155 | pathNodes[sprite.loc][sprite.dir] = PathNodeInfo{.cheapestPathCost = 0, .estimatedRemainingCost = initialCostGuess}; | 
| 153 | 156 | ||
| 154 | std::priority_queue<SearchNode, std::vector<SearchNode>, std::greater<SearchNode>> openSet; | 157 | std::priority_queue<SearchNode, std::vector<SearchNode>, std::greater<SearchNode>> openSet; | 
| 155 | openSet.emplace(sprite.loc, initialCostGuess); | 158 | openSet.emplace(sprite.loc, sprite.dir, initialCostGuess); | 
| 156 | 159 | ||
| 157 | while (!openSet.empty()) { | 160 | while (!openSet.empty()) { | 
| 158 | SearchNode searchNode = openSet.top(); | 161 | SearchNode searchNode = openSet.top(); | 
| @@ -163,8 +166,7 @@ void BehaviourSystem::createPath(int spriteId) { | |||
| 163 | break; | 166 | break; | 
| 164 | } | 167 | } | 
| 165 | 168 | ||
| 166 | PathNodeInfo& nodeInfo = pathNodes[searchNode.point]; | 169 | PathNodeInfo& nodeInfo = pathNodes[searchNode.point][searchNode.dirFromPreviousPoint]; | 
| 167 | int newCost = nodeInfo.cheapestPathCost + 1; | ||
| 168 | 170 | ||
| 169 | static const std::vector<Direction> allDirections = { | 171 | static const std::vector<Direction> allDirections = { | 
| 170 | Direction::down, | 172 | Direction::down, | 
| @@ -183,9 +185,17 @@ void BehaviourSystem::createPath(int spriteId) { | |||
| 183 | Direction::right }; | 185 | Direction::right }; | 
| 184 | 186 | ||
| 185 | std::vector<Direction> directionList = sprite.cardinalDirectionsOnly ? cardinalDirections : allDirections; | 187 | std::vector<Direction> directionList = sprite.cardinalDirectionsOnly ? cardinalDirections : allDirections; | 
| 186 | directionList.push_back(nodeInfo.dirFromPreviousPoint); | ||
| 187 | |||
| 188 | for (Direction dir : directionList) { | 188 | for (Direction dir : directionList) { | 
| 189 | double newCost = nodeInfo.cheapestPathCost; | ||
| 190 | if (dir != searchNode.dirFromPreviousPoint) { | ||
| 191 | newCost += 0.1; | ||
| 192 | } | ||
| 193 | if (isCardinalDirection(dir)) { | ||
| 194 | newCost += 1; | ||
| 195 | } else { | ||
| 196 | newCost += 1.4; | ||
| 197 | } | ||
| 198 | |||
| 189 | vec2i newPos = searchNode.point + unitVecInDirection(dir) * sprite.movementSpeed; | 199 | vec2i newPos = searchNode.point + unitVecInDirection(dir) * sprite.movementSpeed; | 
| 190 | 200 | ||
| 191 | if (newPos.x() < 0 || newPos.y() < 0 || newPos.x() >= mapBounds.w() || newPos.y() >= mapBounds.h()) { | 201 | if (newPos.x() < 0 || newPos.y() < 0 || newPos.x() >= mapBounds.w() || newPos.y() >= mapBounds.h()) { | 
| @@ -193,7 +203,7 @@ void BehaviourSystem::createPath(int spriteId) { | |||
| 193 | continue; | 203 | continue; | 
| 194 | } | 204 | } | 
| 195 | 205 | ||
| 196 | PathNodeInfo& neighborInfo = pathNodes[newPos]; | 206 | PathNodeInfo& neighborInfo = pathNodes[newPos][dir]; | 
| 197 | 207 | ||
| 198 | if (neighborInfo.cheapestPathCost <= newCost) { | 208 | if (neighborInfo.cheapestPathCost <= newCost) { | 
| 199 | // There is already a faster path through this neighbor. | 209 | // There is already a faster path through this neighbor. | 
| @@ -211,7 +221,7 @@ void BehaviourSystem::createPath(int spriteId) { | |||
| 211 | neighborInfo.previousPoint = searchNode.point; | 221 | neighborInfo.previousPoint = searchNode.point; | 
| 212 | neighborInfo.dirFromPreviousPoint = dir; | 222 | neighborInfo.dirFromPreviousPoint = dir; | 
| 213 | 223 | ||
| 214 | openSet.emplace(newPos, neighborInfo.cheapestPathCost + neighborInfo.estimatedRemainingCost); | 224 | openSet.emplace(newPos, dir, neighborInfo.cheapestPathCost + neighborInfo.estimatedRemainingCost); | 
| 215 | } | 225 | } | 
| 216 | } | 226 | } | 
| 217 | 227 | ||
| @@ -222,10 +232,15 @@ void BehaviourSystem::createPath(int spriteId) { | |||
| 222 | 232 | ||
| 223 | vec2i curPos = sprite.pathfindingDestination; | 233 | vec2i curPos = sprite.pathfindingDestination; | 
| 224 | while (curPos != sprite.loc) { | 234 | while (curPos != sprite.loc) { | 
| 225 | PathNodeInfo& nodeInfo = pathNodes[curPos]; | 235 | const PathNodeInfo* nodeInfo = nullptr; | 
| 226 | if (sprite.path.empty() || sprite.path.front().dir != nodeInfo.dirFromPreviousPoint) { | 236 | for (const auto& pni : pathNodes[curPos]) { | 
| 227 | sprite.path.push_front(PathfindingInstruction{.dir = nodeInfo.dirFromPreviousPoint, .endpoint = curPos}); | 237 | if (nodeInfo == nullptr || pni.second.cheapestPathCost < nodeInfo->cheapestPathCost) { | 
| 238 | nodeInfo = &pni.second; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | if (sprite.path.empty() || sprite.path.front().dir != nodeInfo->dirFromPreviousPoint) { | ||
| 242 | sprite.path.push_front(PathfindingInstruction{.dir = nodeInfo->dirFromPreviousPoint, .endpoint = curPos}); | ||
| 228 | } | 243 | } | 
| 229 | curPos = nodeInfo.previousPoint; | 244 | curPos = nodeInfo->previousPoint; | 
| 230 | } | 245 | } | 
| 231 | } | 246 | } | 
| diff --git a/src/direction.h b/src/direction.h index 325bcaf..86eb31f 100644 --- a/src/direction.h +++ b/src/direction.h | |||
| @@ -120,4 +120,8 @@ inline Direction cardinalDirectionFacingPoint(vec2i point) { | |||
| 120 | } | 120 | } | 
| 121 | } | 121 | } | 
| 122 | 122 | ||
| 123 | inline bool isCardinalDirection(Direction dir) { | ||
| 124 | return (dir == Direction::left || dir == Direction::right || dir == Direction::up || dir == Direction::down); | ||
| 125 | } | ||
| 126 | |||
| 123 | #endif /* end of include guard: DIRECTION_H_AB66A90E */ | 127 | #endif /* end of include guard: DIRECTION_H_AB66A90E */ | 
