| 1152 | } |
| 1153 | |
| 1154 | Maybe<bool> PathController::findPath(ActorMovementController& movementController, Vec2F const& targetPosition) { |
| 1155 | using namespace PlatformerAStar; |
| 1156 | |
| 1157 | // reached the end of the last path and we have a new target position to move toward |
| 1158 | if (m_path && m_edgeIndex == m_path->size() && m_world->geometry().diff(*m_targetPosition, targetPosition).magnitude() > 0.001) { |
| 1159 | reset(); |
| 1160 | m_targetPosition = targetPosition; |
| 1161 | } |
| 1162 | |
| 1163 | // starting a new path, or the target position moved by more than 2 blocks |
| 1164 | if (!m_targetPosition || (!m_path && !m_pathFinder) || m_world->geometry().diff(*m_targetPosition, targetPosition).magnitude() > 2.0) { |
| 1165 | auto grounded = movementController.onGround(); |
| 1166 | if (m_path) { |
| 1167 | // if already moving on a path, collision will be disabled and we can't use MovementController::onGround() to check for ground collision |
| 1168 | auto const groundCollision = CollisionSet{ CollisionKind::Null, CollisionKind::Block, CollisionKind::Slippery, CollisionKind::Platform }; |
| 1169 | grounded = onGround(movementController, movementController.position(), groundCollision); |
| 1170 | } |
| 1171 | if (*movementController.parameters().gravityEnabled && !grounded && !movementController.liquidMovement()) { |
| 1172 | return {}; |
| 1173 | } |
| 1174 | m_startPosition = movementController.position(); |
| 1175 | m_targetPosition = targetPosition; |
| 1176 | m_pathFinder = make_shared<PathFinder>(m_world, movementController.position(), *m_targetPosition, movementController.baseParameters(), m_parameters); |
| 1177 | } |
| 1178 | |
| 1179 | if (!m_pathFinder && m_path && m_edgeIndex == m_path->size()) |
| 1180 | return true; // Reached goal |
| 1181 | |
| 1182 | if (m_pathFinder) { |
| 1183 | auto explored = m_pathFinder->explore(movementController.baseParameters().pathExploreRate.value(100.0)); |
| 1184 | if (explored) { |
| 1185 | auto pathfinder = m_pathFinder; |
| 1186 | m_pathFinder = {}; |
| 1187 | |
| 1188 | if (*explored) { |
| 1189 | auto path = *pathfinder->result(); |
| 1190 | |
| 1191 | float newEdgeTimer = 0.0; |
| 1192 | float newEdgeIndex = 0.0; |
| 1193 | |
| 1194 | // if we have a path already, see if our paths can be merged either by splicing or fast forwarding |
| 1195 | bool merged = false; |
| 1196 | if (m_path && !path.empty()) { |
| 1197 | // try to fast forward on the new path |
| 1198 | size_t i = 0; |
| 1199 | // fast forward from current edge, or the last edge of the path |
| 1200 | auto curEdgeIndex = min(m_edgeIndex, m_path->size() - 1); |
| 1201 | auto& curEdge = m_path->at(curEdgeIndex); |
| 1202 | for (auto& edge : path) { |
| 1203 | if (curEdge.action == edge.action && curEdge.source.position == edge.source.position && edge.target.position == edge.target.position) { |
| 1204 | // fast forward on the new path |
| 1205 | newEdgeTimer = m_edgeTimer; |
| 1206 | newEdgeIndex = i; |
| 1207 | |
| 1208 | merged = true; |
| 1209 | break; |
| 1210 | } |
| 1211 | i++; |