您的位置:首页 >C++实现A\*寻路算法详解
发布于2026-01-31 阅读(0)
扫一扫,手机访问
A*寻路算法是C++游戏开发中最常用、最实用的路径搜索算法,适用于网格地图或图结构,兼顾效率与最优性;核心用优先队列(按f=g+h排序)、哈希表(查重与父节点映射),启发式推荐曼哈顿距离(4向)或对角距离(8向)。

在C++游戏开发中,A*(A-star)寻路算法是最常用、最实用的路径搜索算法之一。它兼顾效率与最优性,适合网格地图(如2D方格、Tile地图)或图结构中的单位移动规划。下面直接给出一个轻量、可读性强、带注释的C++实现,基于标准库,不依赖第三方引擎,可直接集成进你的游戏项目。
要高效运行A*,需三个关键容器:
std::priority_queue(最小堆),按 f(n) = g(n) + h(n) 排序std::unordered_set(哈希表)快速查重std::unordered_map记录每个节点的前驱,用于回溯路径对网格地图,推荐使用曼哈顿距离(4向移动)或欧几里得距离(8向/斜向移动)。避免用错导致非最优或变慢:
abs(x1-x2) + abs(y1-y2)max(abs(x1-x2), abs(y1-y2))(更准且快)以下代码支持 2D 网格(int 类型障碍物标记),输出最短路径坐标序列:
#include <iostream> #include <vector> #include <queue> #include <unordered_set> #include <unordered_map> #include <cmath> #include <algorithm>struct Point { int x, y; bool operator==(const Point& o) const { return x == o.x && y == o.y; } };
// 哈希特化,用于 unordered_set/map namespace std { template<> struct hash<Point> { size_t operator()(const Point& p) const { return hash<int>{}(p.x) ^ (hash<int>{}(p.y) << 1); } }; }
// A* 节点(优先队列元素) struct Node { Point pos; float f, g; bool operator>(const Node& rhs) const { return f > rhs.f; } };
std::vector<Point> astar(const std::vector<std::vector<int>>& grid, Point start, Point end) { if (grid.empty() || grid[0].empty()) return {};
int rows = grid.size(), cols = grid[0].size(); auto in_bounds = [&](int x, int y) { return x >= 0 && x < rows && y >= 0 && y < cols; }; auto is_walkable = [&](int x, int y) { return in_bounds(x, y) && grid[x][y] == 0; // 0=空地,1=障碍 }; // 启发式:对角距离(8向) auto heuristic = [&](Point a, Point b) -> float { int dx = abs(a.x - b.x), dy = abs(a.y - b.y); return std::max(dx, dy) + (std::sqrt(2.0f) - 1.0f) * std::min(dx, dy); }; std::priority_queue<Node, std::vector<Node>, std::greater<Node>> open; std::unordered_set<Point> closed; std::unordered_map<Point, Point> came_from; std::unordered_map<Point, float> g_score; open.push({start, heuristic(start, end), 0}); g_score[start] = 0; const std::vector<std::pair<int,int>> dirs = { {-1,0},{1,0},{0,-1},{0,1}, // 上下左右 {-1,-1},{-1,1},{1,-1},{1,1} // 对角(可选,注释掉即4向) }; while (!open.empty()) { Node curr = open.top(); open.pop(); if (curr.pos == end) break; if (closed.count(curr.pos)) continue; closed.insert(curr.pos); for (auto [dx, dy] : dirs) { Point next{curr.pos.x + dx, curr.pos.y + dy}; if (!is_walkable(next.x, next.y)) continue; float move_cost = (dx == 0 || dy == 0) ? 1.0f : std::sqrt(2.0f); float tentative_g = g_score[curr.pos] + move_cost; if (!g_score.count(next) || tentative_g < g_score[next]) { came_from[next] = curr.pos; g_score[next] = tentative_g; float f = tentative_g + heuristic(next, end); open.push({next, f, tentative_g}); } } } // 回溯路径 std::vector<Point> path; for (Point curr = end; curr != start && came_from.count(curr); curr = came_from[curr]) { path.push_back(curr); } if (!path.empty() && path.back() != start) path.push_back(start); std::reverse(path.begin(), path.end()); return path;}
// 示例用法 int main() { // 0=可通过,1=墙 std::vector<std::vector<int>> map = { {0,0,0,0,1}, {0,1,0,0,0}, {0,1,0,1,0}, {0,0,0,1,0}, {1,0,0,0,0} };
auto path = astar(map, {0,0}, {4,4}); std::cout << "Path: "; for (auto p : path) std::cout << "(" << p.x << "," << p.y << ") "; std::cout << "\n";}
Point换成你引擎的向量类型(如sf::Vector2i、glm::ivec2),重载==和hashgrid参数改为接口抽象(如auto getCell(x,y) -> CellType),支持动态地形或NavMesh采样基本上就这些。A*本身不复杂,但细节(比如启发式选择、移动代价建模、内存管理)容易忽略,影响性能和路径质量。实际项目中常配合路径缓存、分层寻路(Hierarchical A*)或Flow Field做大规模单位调度——那是进阶方向了。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9