js+ajax实现的A*游戏路径算法整理

关于“js+ajax实现的A*游戏路径算法整理”的完整攻略,以下是详细介绍(注意,为了方便阅读,带有代码块的内容使用了代码语法高亮):

什么是A*算法?

A*算法是一种基于图形、搜索和启发式运算的寻路算法,通常用于从起点到目标点的最优路径搜索。

A*算法的要点

A*算法将费用(距离、代价)与启发式函数两者结合,来评估当前节点到目标点路径的可能代价大小。其中启发式函数具有预测未来路径代价的功能。

  • 当问题没有特殊限制时,最好采用A算法进行搜索,而像树状图,网格状图等结构问题,A算法可以简单快速地处理。
  • 一般情况下,用A*算法所得到的解决答案是最优解。但有时会出现因方向不同而产生的误差,故也不一定保证绝对最优解。

A*算法伪代码

1.置入起始点。
2.置起始点的f=0,算法对已处理的部分为0,未处理部分为无限制。
3.若终止则结束。
4.选取“未处理”状态中f值最小的点做为当前节点。
5.将当前节点从“未处理”中删除,放入“已处理”中。
6.扩展当前节点。
7.若候选节点中已存在于已处理表,或未处理表f值比当前节点要小,则删除该节点。
8.将本次扩展得到的所有节点按f值排序后,加入未处理节点。

实现A*算法的示例

示例#1:A*算法在地图寻路中的应用

下面是一段基于A*算法的JavaScript代码,实现了地图寻路的功能,具体实现过程详见注释:

// 定义地图类
class Map {
    constructor() {
        this.map = mapData; // 初始化地图数据
        this.start = null; // 起点
        this.end = null; // 终点
    }

    // 计算当前点到终点的曼哈顿距离
    calcManhattan(point) {
        const dx = Math.abs(point.x - this.end.x);
        const dy = Math.abs(point.y - this.end.y);
        return dx + dy;
    }

    // 查找当前点的八个相邻节点
    findNeighbor(point) {
        const w = this.map[0].length;
        const h = this.map.length;
        const neighbor = [];

        for (let i = point.x - 1; i <= point.x + 1; i++) {
            for (let j = point.y - 1; j <= point.y + 1; j++) {
                if (i >= 0 && i < h && j >= 0 && j < w && (i != point.x || j != point.y) && this.map[i][j] != 1) {
                    neighbor.push({x: i, y: j});
                }
            }
        }

        return neighbor;
    }

    //寻路
    findPath() {
        let openList = [];
        let closedList = [];

        openList.push(this.start); // 起点放入openList

        while (openList.length) { // 当openList不为空时
            let minIndex = 0;
            // 找到f(n)=g(n)+h(n)最小的节点作为当前节点
            for (let i = 0; i < openList.length; i++) {
                if (openList[i].f < openList[minIndex].f) {
                    minIndex = i;
                }
            }

            const currentNode = openList[minIndex];  // 当前节点
            // 当前节点为终点时
            if (currentNode.x === this.end.x && currentNode.y === this.end.y) {
                let path = [];
                let node = currentNode;
                while (node) {
                    path.push(node);
                    node = node.parent;
                }
                return path.reverse();
            }

            // 将当前点从`openList`转移到`closedList`
            openList.splice(minIndex, 1);
            closedList.push(currentNode);

            // 扩展相邻节点
            let neighbors = this.findNeighbor(currentNode);
            for (let i = 0; i < neighbors.length; i++) {
                const neighbor = neighbors[i];

                // 如果邻居节点已被访问过或被加入到开启列表中,则继续下一个节点的遍历
                if (closedList.some(v => v.x === neighbor.x && v.y === neighbor.y)
                    || openList.some(v => v.x === neighbor.x && v.y === neighbor.y)) {
                    continue;
                }

                let g = currentNode.g + 1;  // 到达邻居节点的实际代价
                // 确认邻居节点代价是否最优
                let isInOpenList = openList.some(v => v.x === neighbor.x && v.y === neighbor.y);
                let isInClosedList = closedList.some(v => v.x === neighbor.x && v.y === neighbor.y);
                let h = this.calcManhattan(neighbor);  // 当前节点到终点的曼哈顿距离
                let f = g + h; // 总代价

                if (!isInOpenList && !isInClosedList) {
                    openList.push({
                        x: neighbor.x,
                        y: neighbor.y,
                        g,
                        f,
                        parent: currentNode
                    });
                } else if (isInOpenList && g < neighbor.g) {
                    const index = openList.findIndex(v => v.x === neighbor.x && v.y === neighbor.y);
                    openList[index].g = g;
                    openList[index].f = f;
                    openList[index].parent = currentNode;
                } else if (isInClosedList && g < neighbor.g) {
                    const index = closedList.findIndex(v => v.x === neighbor.x && v.y === neighbor.y);
                    closedList[index].g = g;
                    closedList[index].f = f;
                    closedList[index].parent = currentNode;
                    openList.push(closedList[index]);
                    closedList.splice(index, 1);
                }
            }
        }

        return null;
    }
}

// 示例#1的应用
const mapData = [
    [0, 0, 0, 0, 0],
    [0, 0, 0, 1, 0],
    [0, 0, 0, 1, 0],
    [0, 0, 0, 0, 0],
];
const map = new Map();
map.start = { x: 0, y: 0 }; // 起点
map.end = { x: 3, y: 4 }; // 终点
console.log(map.findPath());

示例#2:A*算法的通用实现

下面演示如何用A*算法实现通用的寻路:

class PathFinding {
    constructor() {
        // 地图大小
        this._size = {
            x: 0,
            y: 0
        };
        // 障碍物数组
        this._barriers = [];
    }

    // 初始化地图和障碍物数组
    init(size, barriers) {
        this._size = size;
        this._barriers = barriers;
    }

    //判断是否是障碍物
    isBarrier(x, y) {
        let isBarrier = false;
        for (let i = 0; i < this._barriers.length; i++) {
            if (this._barriers[i].x === x && this._barriers[i].y === y) {
                isBarrier = true;
                break;
            }
        }
        return isBarrier;
    }

    // 计算曼哈顿距离
    calcManhattan(from, to) {
        return Math.abs(to.x - from.x) + Math.abs(to.y - from.y);
    }

    // 查找路径
    findPath(src, dest) {
        let openList = [];
        let closedList = [];
        let startNode = {
            x: src.x,
            y: src.y,
            g: 0, // 实际代价
            h: this.calcManhattan(src, dest), // 估测代价
            f: this.calcManhattan(src, dest), // 总代价
            parent: null
        };
        openList.push(startNode);

        while (openList.length > 0) { // 当openList不为空时
            // 从openList中取出f(n)值最小的作为当前节点
            let currentIndex = 0;
            for (let i = 1; i < openList.length; i++) {
                if (openList[i].f < openList[currentIndex].f) {
                    currentIndex = i;
                }
            }
            let currentNode = openList[currentIndex];

            // 如果找到目标,则返回路径
            if (currentNode.x === dest.x && currentNode.y === dest.y) {
                let path = [];
                let node = currentNode;
                while (node) {
                    path.push(node);
                    node = node.parent;
                }
                return path.reverse();
            }

            // 从openList删除当前节点,加入到closedList
            openList.splice(currentIndex, 1);
            closedList.push(currentNode);

            // 扩展节点
            for (let i = currentNode.x - 1; i <= currentNode.x + 1; i++) {
                for (let j = currentNode.y - 1; j <= currentNode.y + 1; j++) {
                    if (i >= 0 && i < this._size.x && j >= 0 && j < this._size.y 
                        && (i != currentNode.x || j != currentNode.y) && !this.isBarrier(i, j)) {
                        let g = currentNode.g + 1; // 实际代价
                        let h = this.calcManhattan({ x: i, y: j }, dest); // 估测代价
                        let f = g + h; // 总代价
                        let isExistInClosedList = false;
                        for (let k = 0; k < closedList.length; k++) {
                            if (closedList[k].x === i && closedList[k].y === j) {
                                isExistInClosedList = true;
                                break;
                            }
                        }

                        let isExistInOpenList = false;
                        for (let k = 0; k < openList.length; k++) {
                            if (openList[k].x === i && openList[k].y === j) {
                                isExistInOpenList = true;
                                break;
                            }
                        }

                        if (!isExistInClosedList && !isExistInOpenList) {
                            openList.push({
                                x: i,
                                y: j,
                                g,
                                h,
                                f,
                                parent: currentNode
                            })
                        } else if (isExistInOpenList && g < openList[currentIndex].g) {
                            let index = openList.findIndex((value) => value.x === i && value.y === j);
                            openList[index].g = g;
                            openList[index].h = h;
                            openList[index].f = f;
                            openList[index].parent = currentNode;
                        }
                    }
                }
            }
        }
    }
};

// 示例#2的应用
// 定义地图大小和障碍物数组
let size = {x: 6, y: 3};
let barriers = [
    {x: 1, y: 0},
    {x: 1, y: 1},
    {x: 3, y: 0},
    {x: 3, y: 1},
    {x: 4, y: 1},
    {x: 5, y: 1},
];
// 初始化并进行寻路
const pf = new PathFinding();
pf.init(size, barriers);
console.log(pf.findPath({x: 0, y: 0}, {x: 5, y: 2}));

以上是关于js+ajax实现的A*游戏路径算法整理的详细攻略,希望能够帮到你!

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:js+ajax实现的A*游戏路径算法整理 - Python技术站

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

相关文章

  • php过滤HTML标签、属性等正则表达式汇总

    PHP过滤HTML标签、属性等正则表达式汇总 在开发网页或者Web应用的过程中,往往需要对用户提交的数据进行过滤和清理,以防止恶意脚本或病毒的注入,从而保证网站的安全性和稳定性。其中最常见的情况就是过滤HTML标签和属性。本文将介绍PHP中常用的过滤HTML标签、属性等的正则表达式汇总。 过滤HTML标签 PHP中可以使用正则表达式函数preg_replac…

    JavaScript 2023年6月11日
    00
  • 详解jQuery的Cookie插件

    详解jQuery的Cookie插件攻略 1. 介绍 jQuery的Cookie插件是一个实用的、轻量的JavaScript工具,用于操作浏览器中的cookie(饼干)。该插件可用于读取、设置、删除和检查cookie,它为cookie操作提供了简洁的API接口,使得开发者能够轻松地处理cookie数据。 2. 安装 你可以从GitHub上下载该插件的最新版本,…

    JavaScript 2023年6月11日
    00
  • javascript面向对象编程(一) 实例代码

    下面是针对 “javascript面向对象编程(一) 实例代码” 的详细攻略。 1. 阅读并理解代码 首先,我们需要仔细阅读提供的代码,深入理解它的结构、逻辑和运行机制。代码中定义了一个自定义对象 “Person”,其中包含变量和方法定义。在代码中,我们创建了一个 “Person” 实例,使用了对象的属性和方法。 function Person(name, …

    JavaScript 2023年5月18日
    00
  • Jquery解析json数据详解

    Jquery解析json数据详解 JSON(JavaScript Object Notation)是一种轻量级数据交换格式,易于阅读和编写。在web开发中,经常需要将json数据解析并显示在页面上。JQuery可以很方便地处理json数据,本文将详细讲解jquery解析json数据的方法。 1. 获取json数据 首先需要获取json数据,可以从服务器端获取…

    JavaScript 2023年5月27日
    00
  • JS简单获取日期相差天数的方法

    下面是”JS简单获取日期相差天数的方法”的完整攻略。 标题 步骤1:获取两个日期并计算它们之间的毫秒数 首先,我们需要获取两个日期,并计算它们之间的毫秒数。代码如下: const date1 = new Date("2021-03-01") const date2 = new Date("2021-03-05") co…

    JavaScript 2023年5月27日
    00
  • 详解AngularJS Filter(过滤器)用法

    详解AngularJS Filter(过滤器)用法 什么是AngularJS Filter? AngularJS Filter(过滤器) 是AngularJS中的一种自定义组件,它可以对要展示在AngularJS应用程序模板上的数据进行数量、格式和类型等方面的过滤或转换,相当于是数据的预处理器。使用过滤器,可以让我们更加方便,快捷地展示数据。 例如,用户搜索…

    JavaScript 2023年6月10日
    00
  • Javascript入门学习第二篇 js类型第1/2页

    以下是“Javascript入门学习第二篇 js类型第1/2页”的完整攻略: Javascript类型 Javascript是一种弱类型语言,因此不需要在声明变量时指定变量的类型。Javascript中的类型可以分为以下几类: 原始类型(primitive types):包括数字(number)、字符串(string)、布尔值(boolean)、空(null…

    JavaScript 2023年6月10日
    00
  • 浅谈javascript如何获取文件后缀名

    下面是“浅谈JavaScript如何获取文件后缀名”的完整攻略: 1.什么是文件后缀名 文件后缀名是指在文件名的最后一个句点(.)后面的几个字符,用来表示该文件的类型。比如说,图片文件的后缀名通常是“jpg”或“png”,文本文件的后缀名通常是“txt”或“md”,等等。 2.如何获取文件后缀名 在JavaScript中,可以通过字符串的方法来获取文件后缀名…

    JavaScript 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部