全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

c++如何实现A*寻路算法_c++游戏开发常用算法【源码】

A*寻路算法是C++游戏开发中最常用、最实用的路径搜索算法,适用于网格地图或图结构,兼顾效率与最优性;核心用优先队列(按f=g+h排序)、哈希表(查重与父节点映射),启发式推荐曼哈顿距离(4向)或对角距离(8向)。

在C++游戏开发中,A*(A-star)寻路算法是最常用、最实用的路径搜索算法之一。它兼顾效率与最优性,适合网格地图(如2D方格、Tile地图)或图结构中的单位移动规划。下面直接给出一个轻量、可读性强、带注释的C++实现,基于标准库,不依赖第三方引擎,可直接集成进你的游戏项目。

核心数据结构设计

要高效运行A*,需三个关键容器:

  • 开放列表(open set):待评估节点,用std::priority_queue(最小堆),按 f(n) = g(n) + h(n) 排序
  • 关闭列表(closed set):已处理节点,用std::unordered_set(哈希表)快速查重
  • 父节点映射(came_from):用std::unordered_map记录每个节点的前驱,用于回溯路径

启发式函数 h(n) 的选择

对网格地图,推荐使用曼哈顿距离(4向移动)或欧几里得距离(8向/斜向移动)。避免用错导致非最优或变慢:

  • 4方向(上下左右)→ 用曼哈顿:abs(x1-x2) + abs(y1-y2)
  • 8方向(含对角线)→ 用对角距离:max(abs(x1-x2), abs(y1-y2))(更准且快)
  • 不建议直接用欧氏距离平方(会失去可容许性),若要用请开根号并确保浮点精度可控

完整可运行示例(控制台版)

以下代码支持 2D 网格(int 类型障碍物标记),输出最短路径坐标序列:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

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 { size_t operator()(const Point& p) const { return hash{}(p.x) ^ (hash{}(p.y) << 1); } }; }

// A* 节点(优先队列元素) struct Node { Point pos; float f, g; bool operator>(const Node& rhs) const { return f > rhs.f; } };

std::vector astar(const std::vector>& 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 youjiankuohaophpcn= 0 && x zuojiankuohaophpcn rows && y youjiankuohaophpcn= 0 && y zuojiankuohaophpcn 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) -youjiankuohaophpcn 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_queuezuojiankuohaophpcnNode, std::vectorzuojiankuohaophpcnNodeyoujiankuohaophpcn, std::greaterzuojiankuohaophpcnNodeyoujiankuohaophpcnyoujiankuohaophpcn open;
std::unordered_setzuojiankuohaophpcnPointyoujiankuohaophpcn closed;
std::unordered_mapzuojiankuohaophpcnPoint, Pointyoujiankuohaophpcn came_from;
std::unordered_mapzuojiankuohaophpcnPoint, floatyoujiankuohaophpcn g_score;

open.push({start, heuristic(start, end), 0});
g_score[start] = 0;

const std::vectorzuojiankuohaophpcnstd::pairzuojiankuohaophpcnint,intyoujiankuohaophpcnyoujiankuohaophpcn 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 zuojiankuohaophpcn 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::vectorzuojiankuohaophpcnPointyoujiankuohaophpcn 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<:vector>> 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 zuojiankuohaophpcnzuojiankuohaophpcn "Path: ";
for (auto p : path) std::cout zuojiankuohaophpcnzuojiankuohaophpcn "(" zuojiankuohaophpcnzuojiankuohaophpcn p.x zuojiankuohaophpcnzuojiankuohaophpcn "," zuojiankuohaophpcnzuojiankuohaophpcn p.y zuojiankuohaophpcnzuojiankuohaophpcn ") ";
std::cout zuojiankuohaophpcnzuojiankuohaophpcn "\n";

}

集成到游戏项目的建议

  • Point换成你引擎的向量类型(如sf::Vector2iglm::ivec2),重载==hash
  • grid参数改为接口抽象(如auto getCell(x,y) -> CellType),支持动态地形或NavMesh采样
  • 加早停机制:设置最大搜索节点数(防卡死)或时间片(如每帧只算50个节点)
  • 路径平滑:对返回的折线路径做直线检测+跳点(JPS)或贝塞尔插值,提升视觉自然度

基本上就这些。A*本身不复杂,但细节(比如启发式选择、移动代价建模、内存管理)容易忽略,影响性能和路径质量。实际项目中常配合路径缓存、分层寻路(Hierarchical A*)或Flow Field做大规模单位调度——那是进阶方向了。


# node  # go  # ai  # c++  # ios  # stream  # 游戏开发  # cos  # 标准库  # red  # auto  # int  # 数据结构  # 接口  #   # map  # 算法  # 曼哈顿  # 最优  # 上下左右  # 最常用  # 欧几里得  # 进阶  # 特化  # 那是  # 浮点 


相关文章: 建站之星图片链接生成指南:自助建站与智能设计教程  linux top下的 minerd 木马清除方法  ,想在网上投简历,哪几个网站比较好?  ,石家庄四十八中学官网?  如何确保西部建站助手FTP传输的安全性?  广平建站公司哪家专业可靠?如何选择?  高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  html制作网站的步骤有哪些,iapp如何添加网页?  如何用5美元大硬盘VPS安全高效搭建个人网站?  儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?  详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  高性能网站服务器配置指南:安全稳定与高效建站核心方案  建站之星×万网:智能建站系统+自助建站平台一键生成  表情包在线制作网站免费,表情包怎么弄?  桂林网站制作公司有哪些,桂林马拉松怎么报名?  威客平台建站流程解析:高效搭建教程与设计优化方案  如何在云主机上快速搭建多站点网站?  高防服务器租用如何选择配置与防御等级?  建站之星展会模板:智能建站与自助搭建高效解决方案  专业网站建设制作报价,网页设计制作要考什么证?  如何用PHP工具快速搭建高效网站?  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  临沂网站制作企业,临沂第三中学官方网站?  Android使用GridView实现日历的简单功能  广州网站建站公司选择指南:建站流程与SEO优化关键词解析  如何通过西部建站助手安装IIS服务器?  非常酷的网站设计制作软件,酷培ai教育官方网站?  制作门户网站的参考文献在哪,小说网站怎么建立?  如何通过FTP空间快速搭建安全高效网站?  如何用wdcp快速搭建高效网站?  网站制作话术技巧,网站推广做的好怎么话术?  正规网站制作公司有哪些,目前国内哪家网页网站制作设计公司比较专业靠谱?口碑好?  网站建设制作需要多少钱费用,自己做一个网站要多少钱,模板一般多少钱?  如何用免费手机建站系统零基础打造专业网站?  TestNG的testng.xml配置文件怎么写  西安专业网站制作公司有哪些,陕西省建行官方网站?  制作网站的公司有哪些,做一个公司网站要多少钱?  如何在腾讯云服务器快速搭建个人网站?  哈尔滨网站建设策划,哈尔滨电工证查询网站?  如何在局域网内绑定自建网站域名?  潮流网站制作头像软件下载,适合母子的网名有哪些?  如何快速搭建高效可靠的建站解决方案?  小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?  网站制作专业公司有哪些,如何制作一个企业网站,建设网站的基本步骤有哪些?  建站OpenVZ教程与优化策略:配置指南与性能提升  代购小票制作网站有哪些,购物小票的简要说明?  文字头像制作网站推荐软件,醒图能自动配文字吗?  如何获取免费开源的自助建站系统源码? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。