A星寻路的平滑处理 c++实现

RPG游戏离不开寻路 A星寻路是游戏的最短路径寻路算法。

网上有很多A*寻路的源码,我学习了几份,发现它们都没有对路径进行平滑处理,路径都是不平滑的  这样游戏角色寻路走路会很怪异。看到别人博客思路,自己用c++撸一遍 

我的起点为 0,0点 终点为9,6点

思路借鉴:https://blog.csdn.net/m0_37290785/article/details/79655666

//初始化地图数据
    int **map = new int*[10];
    for (int i = 0; i < 10; i++)//为指针数组的每个元素分配一个数组
        map[i] = new int[10];
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            map[i][j] = 0;
        }
    }
    map[2][0] = 1;
    map[2][1] = 1;
    map[2][2] = 1;
    map[2][3] = 1;
    map[2][4] = 1;
    map[2][5] = 1;
    map[2][6] = 1;
    map[4][10] = 1;
    map[4][9] = 1;
    map[4][8] = 1;
    map[4][7] = 1;
    map[4][6] = 1;
    map[4][5] = 1;
    map[4][4] = 1;

Astar astar;

astar.setDataByMap(map, 10, 10);

std::vector<MapReader::sVec2> path =astar.findAstart(9, 6,0, 0);

看下图的8是原生的的路径。  

怎么去优化呢。

第一步比较简单删去路径上的共线点  这些共线点已经没有意义了

//1.将路径去掉共线点
    int max = path.size() - 2;
    for (int i = 0; i <max; )
    {
        if ((path[i].x * path[i + 1].y - path[i + 2].y * path[i].x) + (path[i + 1].x * path[i + 2].y - path[i].y * path[i + 1].x) + (path[i + 2].x * path[i].y - path[i + 2].x * path[i + 1].y) == 0)//判断三点共线
        {
            path.erase(path.begin() + i + 1);
            max = path.size() - 2;
        }
        else
        {
            i++;
        }

    }

然后我得出了下图路径 

第二步,去掉多余拐点,这一步复杂一点,需要判断两节点是否能够直达,若能直达五障碍物即可删除二者的中间节点,可以参考https://blog.csdn.net/midashao/article/details/70237061

然后就得到了最终路径

//2.判断是否直达
    cout << "删除多余路径过程" << endl;
    int max1 = path.size() - 2;
    for (int i = 0; i < max1; )
    {
        bool okjudge = true;
        //获取两点之间斜率
        if (path[i].x == path[i + 2].x || path[i].y == path[i + 2].y)
        {
            cout << i << "斜率0或90" << endl;
            i++;
            continue;
        }
        float k = float(path[i + 2].x - path[i].x) / float(path[i + 2].y - path[i].y);
        float b = path[i].x + 0.5 - k * (path[i].y + 0.5);
        cout << i << "斜率K:" << k << " b:" << b << endl;
        if (fabs(k) <= 1)
        {
            if (k > 0 && path[i + 2].y > path[i].y || k<0 && path[i + 2].y > path[i].y)
            {
                cout << "斜率小于等于45度 " << endl;
                //斜率小于45度
                //获取宽度差
                int width = fabs(path[i + 2].y - path[i].y);
                for (int j = 0; j < width; j++)
                {
                    float y = (1 + path[i].y + j) * k + b;
                    cout << y << endl;
                    if (y != int(y))//y不是整数
                    {
                        cout << path[i].y + j << " " << int(y) << "   " << path[i].y + j + 1 << " " << int(y) << endl;
                        cout << "1:   " << g_Map[path[i].y + j][int(y)].iColor << " " << g_Map[path[i].y + j + 1][int(y)].iColor << endl;
                        if (g_Map[path[i].y + j][int(y)].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }
                        if (g_Map[path[i].y + j + 1][int(y)].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }

                    }
                    else
                    {

                    }
                }

            }
            else if (k<0 && path[i + 2].y < path[i].y || k>0 && path[i + 2].y < path[i].y)
            {
                cout << "斜率小于等于45度 " << endl;
                //斜率小于45度
                //获取宽度差
                int width = fabs(path[i + 2].y - path[i].y);
                for (int j = 0; j < width; j++)
                {
                    float y = (0.5 + path[i].y - 0.5 - j) * k + b;
                    cout << y << endl;
                    if (y != int(y))//y不是整数
                    {
                        cout << path[i].y - j << " " << int(y) << "   " << path[i].y - j - 1 << " " << int(y) << endl;
                        cout << "1:   " << g_Map[path[i].y - j][int(y)].iColor << " " << g_Map[path[i].y - j - 1][int(y)].iColor << endl;
                        if (g_Map[path[i].y - j][int(y)].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }
                        if (g_Map[path[i].y - j - 1][int(y)].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }

                    }
                    else
                    {

                    }
                }
            }
        }
        else
        {
            if (k > 0 && path[i + 2].x > path[i].x || k<0 && path[i + 2].x > path[i].x)
            {
                cout << "斜率大于45度" << endl;
                //斜率大于45度
                //获取高度差
                int height = fabs(path[i + 2].x - path[i].x);
                for (int j = 0; j < height; j++)
                {
                    float x = ((0.5 + path[i].x + 0.5 + j) - b) / k;
                    cout << x << endl;
                    if (x != int(x))
                    {
                        cout << int(x) << " " << path[i].x + j << "   " << int(x) << " " << path[i].x + j + 1 << endl;
                        cout << "2:     " << g_Map[int(x)][path[i].x + j].iColor << " " << g_Map[int(x)][path[i].x + j + 1].iColor << endl;
                        if (g_Map[int(x)][path[i].x + j].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }
                        if (g_Map[int(x)][path[i].x + j + 1].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }

                    }
                    else
                    {

                    }
                }
            }
            else if (k<0 && path[i + 2].x < path[i].x || k>0 && path[i + 2].x < path[i].x)
            {
                cout << "斜率大于45度" << endl;
                int height = fabs(path[i + 2].x - path[i].x);
                for (int j = 0; j < height; j++)
                {
                    float x = ((0.5 + path[i].x - 0.5 - j) - b) / k;
                    cout << x << endl;
                    if (x != int(x))
                    {
                        cout << int(x) << " " << path[i].x - j << "   " << int(x) << " " << path[i].x - j - 1 << endl;
                        cout << "2:     " << g_Map[int(x)][path[i].x - j].iColor << " " << g_Map[int(x)][path[i].x - j - 1].iColor << endl;
                        if (g_Map[int(x)][path[i].x - j].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }
                        if (g_Map[int(x)][path[i].x - j - 1].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }

                    }
                    else
                    {

                    }
                }
            }

        }
        if (okjudge == false)
        {
            i++;
        }
        else
        {
            cout << "删除节点成功" << endl;
            path.erase(path.begin() + i + 1);
            max1 = path.size() - 2;
        }
    }

 

 

最后将两步封装成寻路的一个成员函数。就可以随时调用了

std::vector<MapReader::sVec2> Astar::pathCreat(std::vector<MapReader::sVec2> path)
{
    //1.将路径去掉共线点
    int max = path.size() - 2;
    for (int i = 0; i <max; )
    {
        if ((path[i].x * path[i + 1].y - path[i + 2].y * path[i].x) + (path[i + 1].x * path[i + 2].y - path[i].y * path[i + 1].x) + (path[i + 2].x * path[i].y - path[i + 2].x * path[i + 1].y) == 0)//判断三点共线
        {
            path.erase(path.begin() + i + 1);
            max = path.size() - 2;
        }
        else
        {
            i++;
        }

    }
    cout << "去掉共线点路径打印" << endl;
    for (int i = 0; i < path.size(); i++)
    {
        cout << "路径" << i << ": " << path[i].y << "," << path[i].x << endl;
    }

    //2.判断是否直达
    cout << "删除多余路径过程" << endl;
    int max1 = path.size() - 2;
    for (int i = 0; i < max1; )
    {
        bool okjudge = true;
        //获取两点之间斜率
        if (path[i].x == path[i + 2].x || path[i].y == path[i + 2].y)
        {
            cout << i << "斜率0或90" << endl;
            i++;
            continue;
        }
        float k = float(path[i + 2].x - path[i].x) / float(path[i + 2].y - path[i].y);
        float b = path[i].x + 0.5 - k * (path[i].y + 0.5);
        cout << i << "斜率K:" << k << " b:" << b << endl;
        if (fabs(k) <= 1)
        {
            if (k > 0 && path[i + 2].y > path[i].y || k<0 && path[i + 2].y > path[i].y)
            {
                cout << "斜率小于等于45度 " << endl;
                //斜率小于45度
                //获取宽度差
                int width = fabs(path[i + 2].y - path[i].y);
                for (int j = 0; j < width; j++)
                {
                    float y = (1 + path[i].y + j) * k + b;
                    cout << y << endl;
                    if (y != int(y))//y不是整数
                    {
                        cout << path[i].y + j << " " << int(y) << "   " << path[i].y + j + 1 << " " << int(y) << endl;
                        cout << "1:   " << g_Map[path[i].y + j][int(y)].iColor << " " << g_Map[path[i].y + j + 1][int(y)].iColor << endl;
                        if (g_Map[path[i].y + j][int(y)].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }
                        if (g_Map[path[i].y + j + 1][int(y)].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }

                    }
                    else
                    {

                    }
                }

            }
            else if (k<0 && path[i + 2].y < path[i].y || k>0 && path[i + 2].y < path[i].y)
            {
                cout << "斜率小于等于45度 " << endl;
                //斜率小于45度
                //获取宽度差
                int width = fabs(path[i + 2].y - path[i].y);
                for (int j = 0; j < width; j++)
                {
                    float y = (0.5 + path[i].y - 0.5 - j) * k + b;
                    cout << y << endl;
                    if (y != int(y))//y不是整数
                    {
                        cout << path[i].y - j << " " << int(y) << "   " << path[i].y - j - 1 << " " << int(y) << endl;
                        cout << "1:   " << g_Map[path[i].y - j][int(y)].iColor << " " << g_Map[path[i].y - j - 1][int(y)].iColor << endl;
                        if (g_Map[path[i].y - j][int(y)].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }
                        if (g_Map[path[i].y - j - 1][int(y)].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }

                    }
                    else
                    {

                    }
                }
            }
        }
        else
        {
            if (k > 0 && path[i + 2].x > path[i].x || k<0 && path[i + 2].x > path[i].x)
            {
                cout << "斜率大于45度" << endl;
                //斜率大于45度
                //获取高度差
                int height = fabs(path[i + 2].x - path[i].x);
                for (int j = 0; j < height; j++)
                {
                    float x = ((0.5 + path[i].x + 0.5 + j) - b) / k;
                    cout << x << endl;
                    if (x != int(x))
                    {
                        cout << int(x) << " " << path[i].x + j << "   " << int(x) << " " << path[i].x + j + 1 << endl;
                        cout << "2:     " << g_Map[int(x)][path[i].x + j].iColor << " " << g_Map[int(x)][path[i].x + j + 1].iColor << endl;
                        if (g_Map[int(x)][path[i].x + j].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }
                        if (g_Map[int(x)][path[i].x + j + 1].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }

                    }
                    else
                    {

                    }
                }
            }
            else if (k<0 && path[i + 2].x < path[i].x || k>0 && path[i + 2].x < path[i].x)
            {
                cout << "斜率大于45度" << endl;
                int height = fabs(path[i + 2].x - path[i].x);
                for (int j = 0; j < height; j++)
                {
                    float x = ((0.5 + path[i].x - 0.5 - j) - b) / k;
                    cout << x << endl;
                    if (x != int(x))
                    {
                        cout << int(x) << " " << path[i].x - j << "   " << int(x) << " " << path[i].x - j - 1 << endl;
                        cout << "2:     " << g_Map[int(x)][path[i].x - j].iColor << " " << g_Map[int(x)][path[i].x - j - 1].iColor << endl;
                        if (g_Map[int(x)][path[i].x - j].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }
                        if (g_Map[int(x)][path[i].x - j - 1].iColor == true)
                        {
                            okjudge = false;
                            break;
                        }

                    }
                    else
                    {

                    }
                }
            }

        }
        if (okjudge == false)
        {
            i++;
        }
        else
        {
            cout << "删除节点成功" << endl;
            path.erase(path.begin() + i + 1);
            max1 = path.size() - 2;
        }
    }
    return path;
}

 使用只需要包裹下就ok了

    Astar astar;
    astar.setDataByMap(map, 10, 10);
    std::vector<MapReader::sVec2> path = astar.pathCreat(astar.findAstart(9, 6,0, 0));

当然我的代码还存在一定的缺陷= =。忘大佬评论指出不足之处。

 

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
以下是一个简单的C++ A寻路代码实现: ```cpp #include <iostream> #include <queue> #include <vector> #include <cmath> using namespace std; const int INF = 1e9; // 无穷大 const int MAXN = 1005; // 最大节点数 struct Node { int x, y; // 坐标 int g, h; // 距离起点的代价g和距离终点的代价h int f() const { // 总代价f return g + h; } }; int n, m; // 地图大小 char map[MAXN][MAXN]; // 地图 Node start, end; // 起点和终点 int vis[MAXN][MAXN]; // 是否访问过 // 估算距离函数,这里取曼哈顿距离 int estimate(int x1, int y1, int x2, int y2) { return abs(x1 - x2) + abs(y1 - y2); } // A*搜索函数 int astar() { priority_queue<pair<int, Node>> Q; // 优先队列 Q.push(make_pair(0, start)); while (!Q.empty()) { Node u = Q.top().second; Q.pop(); if (u.x == end.x && u.y == end.y) { // 找到终点 return u.g; } if (vis[u.x][u.y]) { // 已经访问过,跳过 continue; } vis[u.x][u.y] = 1; // 标记为已访问 // 枚举相邻节点 for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { if (dx == 0 && dy == 0) { continue; } int nx = u.x + dx, ny = u.y + dy; if (nx < 0 || nx >= n || ny < 0 || ny >= m) { continue; // 超出边界 } if (map[nx][ny] == '#') { continue; // 障碍物 } Node v = {nx, ny, u.g + 1, estimate(nx, ny, end.x, end.y)}; Q.push(make_pair(-v.f(), v)); // 插入队列,优先级为f的相反数 } } } return -1; // 没有找到路径 } int main() { cin >> n >> m; for (int i = 0; i < n; i++) { cin >> map[i]; for (int j = 0; j < m; j++) { if (map[i][j] == 'S') { start = {i, j, 0, 0}; } if (map[i][j] == 'E') { end = {i, j, 0, 0}; } } } int ans = astar(); if (ans == -1) { cout << "No path found." << endl; } else { cout << "The shortest path is " << ans << "." << endl; } return 0; } ``` 该代码实现了一个简单的A寻路算法,包括估算距离函数、A搜索函数和主函数。其中使用了STL的priority_queue来实现优先队列。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值