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 */ |