JS/HTML5游戏常用算法之路径搜索算法 A*寻路算法完整实例

非常感谢你对于本站文章的关注。下面是针对文章“JS/HTML5游戏常用算法之路径搜索算法 A*寻路算法完整实例”的完整攻略解析。

1. 介绍

本文主要讲解的是一种常用于解决路径搜索问题的算法—— A*寻路算法。使用该算法可以在搜索空间(如地图、游戏场景等)中找到一条最优路径,可应用于许多领域,如自动驾驶、游戏AI等。

2. 算法流程

该算法通过在搜索空间中创建一个节点集来实现。

  • 先将起点加入节点集。
  • 从节点集中选取离起点最近的节点,计算其相邻节点的路径距离,如果路径距离加上该节点到起点的距离小于该相邻节点到起点的距离,那么更新该相邻节点到起点的距离,并将该节点加入节点集。
  • 重复步骤2,直到到达终点或搜索完所有节点。

3. 代码实现

该算法实现中,需定义地图和节点对象。

//定义地图对象
var map = {
    width: 10,
    height: 10,
    obstacles: [{x:3,y:3},{x:4,y:3},{x:5,y:3},{x:4,y:4}]
};

//定义节点对象
function node(x, y, endX, endY) {
    this.x = x; //节点横坐标
    this.y = y; //节点纵坐标
    this.g = 0; //起点到当前节点的距离
    this.h = Math.abs(endX - x) + Math.abs(endY - y); //当前节点到终点的估算距离
    this.f = this.g + this.h; //节点综合评价函数
    this.parent = null; //当前节点的父节点
}

以上实现是一个简单示例,地图的width和height分别为地图的宽度和高度,obstacles表示地图上的障碍物,使用数组形式存储,每个障碍物包含x和y属性表示该障碍物在地图上的位置信息。节点对象包括x、y、g、h、f和parent属性。其中g表示起点到当前节点的距离,h表示当前节点到终点的估算距离,f表示g和h的综合评价函数,parent表示当前节点的父节点。

在实现中需要定义开始节点和结束节点,调用寻路函数进行搜索。

//开始节点
var start = new node(0, 0, 9, 9);

//结束节点
var end = new node(9, 9, 9, 9);

//寻路函数
function findPath(start, end) {
    var openList = [start]; //节点集合(初始状态只包含起点)
    var closedList = []; //已处理节点集合

    while (openList.length > 0) {
        //找到f值最小的节点
        var node = openList[0];
        for (var i = 1; i < openList.length; i++) {
            if (openList[i].f < node.f) {
                node = openList[i];
            }
        }

        //将该节点从节点集中删除并加入已处理集合
        openList.splice(openList.indexOf(node), 1);
        closedList.push(node);

        //如果该节点为终点
        if (node.x === end.x && node.y === end.y) {
            var path = [];
            while (node.parent) {
                path.push(node);
                node = node.parent;
            }
            return path.reverse();
        }

        //找到该节点相邻的节点,并计算路径距离
        var neighbors = getNeighbors(node, end);
        for (var j = 0; j < neighbors.length; j++) {
            var neighbor = neighbors[j];

            //如果该节点已在已处理集合中则跳过
            if (closedList.indexOf(neighbor) > -1) {
                continue;
            }

            //计算路径距离
            var g = node.g + (neighbor.x === node.x || neighbor.y === node.y ? 10 : 14);

            //如果路径距离加上该节点到终点的距离小于该相邻节点到起点的距离,则更新节点并加入节点集中
            if (g + neighbor.h < neighbor.f) {
                neighbor.g = g;
                neighbor.f = neighbor.g + neighbor.h;
                neighbor.parent = node;
                if (openList.indexOf(neighbor) === -1) {
                    openList.push(neighbor);
                }
            }
        }
    }

    //如果没有找到路径
    return null;
}

//计算当前节点相邻的节点
function getNeighbors(node, end) {
    var neighbors = [];
    var x = node.x,
        y = node.y;

    //左
    if (x > 0 && !(map.obstacles.filter(function(item){return item.x===x-1 && item.y===y}).length>0)){
        neighbors.push(new node(x - 1, y, end.x, end.y));
    }

    //右
    if (x < map.width - 1 && !(map.obstacles.filter(function(item){return item.x===x+1 && item.y===y}).length>0)){
        neighbors.push(new node(x + 1, y, end.x, end.y));
    }

    //上
    if (y > 0 && !(map.obstacles.filter(function(item){return item.x===x && item.y===y-1}).length>0)){
        neighbors.push(new node(x, y - 1, end.x, end.y));
    }

    //下
    if (y < map.height - 1 && !(map.obstacles.filter(function(item){return item.x===x && item.y===y+1}).length>0)){
        neighbors.push(new node(x, y + 1, end.x, end.y));
    }

    //左上
    if (x > 0 && y > 0 && !(map.obstacles.filter(function(item){return item.x===x-1 && item.y===y-1}).length>0)){
        neighbors.push(new node(x - 1, y - 1, end.x, end.y));
    }

    //右上
    if (x < map.width - 1 && y > 0 && !(map.obstacles.filter(function(item){return item.x===x+1 && item.y===y-1}).length>0)){
        neighbors.push(new node(x + 1, y - 1, end.x, end.y));
    }

    //左下
    if (x > 0 && y < map.height - 1 && !(map.obstacles.filter(function(item){return item.x===x-1 && item.y===y+1}).length>0)){
        neighbors.push(new node(x - 1, y + 1, end.x, end.y));
    }

    //右下
    if (x < map.width - 1 && y < map.height - 1 && !(map.obstacles.filter(function(item){return item.x===x+1 && item.y===y+1}).length>0)){
        neighbors.push(new node(x + 1, y + 1, end.x, end.y));
    }

    return neighbors;
}

4. 示例说明

以下是一个示例,以10*10的地图为例,地图中有四个障碍物,起点为左上角,终点为右下角。

0   1   2   3   4   5   6   7   8   9   
1   .   .   .   .   .   .   .   .   .   |   0
2   .   .   .   #   #   #   .   .   .   |   1
3   .   .   .   .   .   .   .   .   .   |   2
4   .   .   .   .   .   .   .   .   .   |   3
5   .   .   .   .   .   .   .   .   .   |   4
6   .   .   .   .   .   .   .   .   .   |   5
7   .   .   .   .   .   .   .   .   .   |   6
8   .   .   .   .   .   .   .   .   .   |   7
9   .   .   .   .   .   .   .   .   .   |   8
                             |  9
      0 1   2   3   4   5   6   7   8   9   

假设障碍物的坐标为对应位置的左上角坐标。

根据以上示例,在调用寻路函数后,实现的输出结果为:

[
    node {x: 9, y: 9, g: 40, h: 0, f: 40, parent: node{x:8,y:8,...}},
    node {x: 8, y: 8, g: 33, h: 2, f: 35, parent: node{x:7,y:7,...}},
    node {x: 7, y: 7, g: 26, h: 4, f: 30, parent: node{x:6,y:6,...}},
    ...
    node {x: 1, y: 1, g: 10, h: 10, f: 20, parent: node{x:0,y:0,...}},
    node {x: 0, y: 0, g: 0, h: 18, f: 18, parent: null}
]

输出结果包含了所有寻找到最短路径的节点。可以从后往前找到起点和终点间所需的节点数,实现路径的绘制。

5. 总结

以上就是本文对 A*寻路算法的完整分析及实现。希望通过阅读本文,读者可以完全了解本算法的实现过程和应用场景。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JS/HTML5游戏常用算法之路径搜索算法 A*寻路算法完整实例 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Python算法绘制特洛伊小行星群实现示例

    下面是“Python算法绘制特洛伊小行星群实现示例”的完整攻略,包含两个示例说明。 1. 安装所需库 在开始绘制特洛伊小行星群之前,首先需要安装所需的Python库,包括numpy、matplotlib和mpl_toolkits.mplot3d等。可以使用以下命令进行安装: pip install numpy pip install matplotlib p…

    算法与数据结构 2023年5月19日
    00
  • Flutter Dart快速排序算法示例详解

    Flutter Dart快速排序算法示例详解 介绍 快速排序是一种排序算法,其基本思想是选择一个基准元素,将数组分成两个子数组,其中一个子数组的元素都比基准元素小,另一个子数组的元素都比基准元素大。然后递归地对两个子数组进行快速排序。 实现步骤 选择一个基准元素,并将其从数组中移除。 遍历数组,将小于基准元素的元素放入一个新的左侧数组中,大于基准元素的元素放…

    算法与数据结构 2023年5月19日
    00
  • C语言冒泡排序算法代码详解

    下面是“C语言冒泡排序算法代码详解”的完整攻略: 1. 冒泡排序算法原理 冒泡排序是一种基础的排序算法,其基本思想是将待排序的数组中的相邻元素两两比较,如果前面的元素大于后面的元素,则交换它们的位置,直到比较完所有元素。这样一轮比较交换之后,最大(或最小)的元素会被放到最后(或最前),然后再对剩下的元素重复以上步骤,直到所有元素都排好序为止。 2. 冒泡排序…

    算法与数据结构 2023年5月19日
    00
  • PHP中数组的三种排序方法分享

    当我们处理大量数据时,数组是非常有用的数据结构。排序是数组常见的操作之一,PHP中提供了三种常用的排序方法,分别是冒泡排序、快速排序和插入排序。接下来,本文将详细介绍这三种方法的实现过程和使用方法。 冒泡排序 冒泡排序是一种简单的排序算法,它重复地遍历要排序的数组,每次比较相邻两个元素,如果顺序不对就交换它们。这样一趟遍历后,就能把最大(或最小)的元素移到最…

    算法与数据结构 2023年5月19日
    00
  • C语言 扩展欧几里得算法代码

    下面我来为你详细讲解一下“C语言 扩展欧几里得算法代码”的完整攻略。 什么是扩展欧几里得算法? 扩展欧几里得算法是求解两个整数 a、b 的最大公约数(Greatest Common Divisor,简称 GCD)的一种算法。该算法可以不仅计算出最大公约数,还可以得到一组关于 a、b 的贝祖等式的整数解和一些运算过程。 算法流程 扩展欧几里得算法的流程如下: …

    算法与数据结构 2023年5月19日
    00
  • Java 直接插入排序的三种实现

    Java 直接插入排序的三种实现 本文将介绍 Java 中直接插入排序的三种实现方式,分别为插入排序、希尔排序和折半插入排序。 插入排序 插入排序是一种简单直观的排序算法,其基本思想是将一个待排序的元素插入到已排好序列中的适当位置。 以下是 Java 中插入排序的实现代码: public static void insertSort(int[] arr) {…

    算法与数据结构 2023年5月19日
    00
  • Java分治归并排序算法实例详解

    Java分治归并排序算法实例详解 什么是分治归并排序算法 分治法是一种算法解决问题的思想,即将一个问题分成若干个小问题,再将小问题分成更小的子问题,直到最后子问题可以很容易地直接求解,原问题的解即子问题的解的合并。归并排序算法采用了分治法思想,将一个要排序的数组分成两个小数组,再将这两个小数组分别排序,最终合并两个有序小数组成为一个有序大数组。 算法流程 分…

    算法与数据结构 2023年5月19日
    00
  • C语言简单实现快速排序

    C语言简单实现快速排序 什么是快速排序? 快速排序(Quicksort)是一种分治的排序算法,由Tony Hoare于1960年提出。快速排序使用两个指针i,j分别指向待排序数组的最左侧和最右侧,以一个值作为基准(pivot),一般为数组的中间值。快速排序的主要思路是将数组中小于基准值的数放到基准值左边,将大于基准值的数放到右边。然后通过递归的方式,对左右两…

    算法与数据结构 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部