Moortiii

A* Pathfinding C++ & SDL2

Nov 24th, 2018
163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.99 KB | None | 0 0
  1. #include <iostream>
  2. #include <SDL2/SDL.h>
  3. #include <set>
  4. #include <queue>
  5. #include <algorithm>
  6. #include <array>
  7.  
  8. #include "Tilemap.h"
  9.  
  10. void drawProgress(Cell* start, Cell* goal, std::vector<Cell*>& resolved, std::vector<Cell*>& unresolved, std::vector<Cell*> path);
  11. void drawPath(std::vector<Cell*>& path);
  12. int heuristic(Cell *a, Cell *b);
  13. void recreatePath(Cell *end, std::vector<Cell *> &path);
  14. SDL_Rect getRect(Cell *cell);
  15.  
  16. int windowWidth = 800;
  17. int windowHeight = 600;
  18. int cellWidth = 10;
  19. int cellHeight = 10;
  20. SDL_Renderer* renderer;
  21.  
  22. // I'd love to animate this still, but while-loops within while-loops often turn out lame
  23. void findPath(Cell* start, Cell* goal, std::vector<Cell*>& path) {
  24.     std::vector<Cell*> unresolved_nodes;
  25.     std::vector<Cell*> resolved_nodes;
  26.  
  27.     unresolved_nodes.push_back(start);
  28.     Cell* current = *unresolved_nodes.begin();
  29.     current->g = 0;
  30.     current->h = heuristic(start, goal);
  31.     current->f = current->g + current->h;
  32.  
  33.     while (!unresolved_nodes.empty()) {
  34.         size_t bestIndex = 0;
  35.  
  36.         // Find the node with the best f-value from the available nodes
  37.         for (size_t i = 0; i < unresolved_nodes.size(); i++) {
  38.             if (unresolved_nodes[i]->f <= unresolved_nodes[bestIndex]->f)
  39.                 bestIndex = i;
  40.         }
  41.  
  42.         current = unresolved_nodes[bestIndex];
  43.  
  44.         if (current == goal) {
  45.             std::cout << "Found the path!" << std::endl;
  46.             recreatePath(goal, path);
  47.         }
  48.  
  49.         // Remove the node from the list of nodes to process
  50.         auto it = std::remove(unresolved_nodes.begin(), unresolved_nodes.end(), current);
  51.         unresolved_nodes.erase(it, unresolved_nodes.end());
  52.         resolved_nodes.push_back(current);
  53.  
  54.         for(auto const& neighbor : current->neighbors) {
  55.  
  56.             // If the node is not in the set of resolved nodes
  57.             if(std::find(resolved_nodes.begin(), resolved_nodes.end(), neighbor) == resolved_nodes.end()) {
  58.                 int tentative_g = current->g + 1;
  59.  
  60.                 bool new_path = false;
  61.  
  62.                 // Check if the node has been processed before and make sure it is not a wall
  63.                 if(std::find(unresolved_nodes.begin(), unresolved_nodes.end(), neighbor) != unresolved_nodes.end()
  64.                     || current->value == 1) {
  65.  
  66.                     if(tentative_g < neighbor->g)
  67.                         neighbor->g = tentative_g;
  68.                 } else {
  69.                     new_path = true;
  70.  
  71.                     neighbor->g = tentative_g;
  72.                     unresolved_nodes.push_back(neighbor);
  73.                 }
  74.  
  75.                 if(new_path) {
  76.                     neighbor->h = heuristic(neighbor, goal);
  77.                     neighbor->f = neighbor->g + neighbor->h;
  78.                     neighbor->previous = current;
  79.                 }
  80.             }
  81.         }
  82.        
  83.         drawProgress(start, goal, resolved_nodes, unresolved_nodes, path);
  84.     }
  85. }
  86.  
  87. std::vector<std::vector<Cell*>> collisionMap;
  88.  
  89. int main() {
  90.     SDL_Window *window = nullptr;
  91.     window = SDL_CreateWindow("Pathfinding", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowWidth,
  92.                               windowHeight, SDL_WINDOW_SHOWN);
  93.  
  94.     renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
  95.  
  96.     SDL_Event event;
  97.  
  98.     Tilemap tilemap(renderer);
  99.     bool loadedCorrectly = tilemap.loadFromFile("resources/maps/normalrooms/floor_1/room_1.json");
  100.  
  101.     if (!loadedCorrectly) {
  102.         std::cout << "Unable to load tilemap. Verify file path to ensure it is set correctly" << std::endl;
  103.     }
  104.  
  105.     collisionMap = tilemap.getCollisionMap();
  106.  
  107.     auto start = collisionMap[0][0];
  108.     auto end = collisionMap[collisionMap.size() - 1][collisionMap[0].size() - 1];
  109.  
  110.     std::vector<Cell*> path;
  111.  
  112.     while (true) {
  113.         SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
  114.         SDL_PollEvent(&event);
  115.  
  116.         if (event.type == SDL_QUIT)
  117.             break;
  118.  
  119.         SDL_RenderClear(renderer);
  120.  
  121.         drawPath(path);
  122.  
  123.         if(path.empty()) {
  124.             findPath(start, end, path);
  125.         }
  126.  
  127.         SDL_RenderPresent(renderer);
  128.     }
  129.  
  130.     return 0;
  131. }
  132.  
  133. void drawProgress(Cell* start, Cell* goal, std::vector<Cell*>& resolved, std::vector<Cell*>& unresolved, std::vector<Cell*> path) {
  134.     for(auto const& open : unresolved) {
  135.         SDL_SetRenderDrawColor(renderer, 0, 150, 150, 255);
  136.         SDL_Rect rect = getRect(open);
  137.         SDL_RenderFillRect(renderer, &rect);
  138.     }
  139.  
  140.     for(auto const& closed : resolved) {
  141.         SDL_SetRenderDrawColor(renderer, 150, 0, 0, 255);
  142.         SDL_Rect rect = getRect(closed);
  143.         SDL_RenderFillRect(renderer, &rect);
  144.     }
  145.  
  146.     for(auto const& edge : path) {
  147.         SDL_SetRenderDrawColor(renderer, 50, 100, 150, 255);
  148.         SDL_Rect rect = getRect(edge);
  149.         SDL_RenderFillRect(renderer, &rect);
  150.     }
  151.  
  152.     SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
  153.     SDL_Rect startRect = getRect(start);
  154.     SDL_RenderFillRect(renderer, &startRect);
  155.  
  156.     SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
  157.     SDL_Rect goalRect = getRect(goal);
  158.     SDL_RenderFillRect(renderer, &goalRect);
  159. }
  160.  
  161. int heuristic(Cell *a, Cell *b) {
  162.     int deltaX = b->x - a->x;
  163.     int deltaY = b->y - a->x;
  164.  
  165.     // We use a heuristic that returns the euclidean distance from point A to B
  166.     return (int)std::sqrt((deltaX * deltaX + deltaY * deltaY));;
  167. }
  168.  
  169. void recreatePath(Cell *end, std::vector<Cell *> &path) {
  170.     Cell *node = end;
  171.     path.push_back(node);
  172.  
  173.     while (node->previous != nullptr) {
  174.         path.push_back(node->previous);
  175.         node = node->previous;
  176.     }
  177. }
  178.  
  179. void drawPath(std::vector<Cell*>& path) {
  180.     for(auto const& edge : path) {
  181.         SDL_SetRenderDrawColor(renderer, 200, 100, 150, 255);
  182.         SDL_Rect rect = getRect(edge);
  183.         SDL_RenderFillRect(renderer, &rect);
  184.     }
  185. }
  186.  
  187. SDL_Rect getRect(Cell *cell) {
  188.     return SDL_Rect{cell->x * cellWidth, cell->y * cellHeight, cellWidth - 1, cellHeight - 1};
  189. }
Advertisement
Add Comment
Please, Sign In to add comment