A星寻路之大话西游2

系列文章目录`

第一章 A星寻路之大话西游2经典版-没地图的洞内自动寻路



前言

	游戏一般都是有场景地图的。但是游戏场景却不提供地图,此时找寻任务坐标就没办法点击小地图后,自动寻路过去。下面,
	以大话西游2经典版为例。

一、A星是什么?

	A星是一个有效的求解最佳路径的搜索算法,一般应用于导航软件的最短路径计算、游戏寻路计算等。
	A星的核心思想就是基于当前坐标,计算周边坐标是否可以移动,然后以周边可移动的坐标,分别作为下一个计算节点,继续计算节点
周围的坐标。如此往复循环,直至获取到终点坐标。然后根据终点坐标,回推出来要走的路径。
    A星算法的核心公式为:F = G + H。G为起点到当前节点的实际代价(距离),H(本文也称曼哈顿距离,使用该函数作为计算)为当
前节点到终点的最短代价(无论下个坐标是否可以通过,都要视为可通过)。F的作用在下面计算过程中将会讲解。

了解了A星的基本用途和核心,下面我们就来图文配合具体讲解下A星的计算过程。

二、计算过程

1.准备工作

0

(白色为可通过区域,黑色为不可通过区域)
1、首先,通过观察上图可知,地图其实就是一个二维数组,我们以左下角为0,0开始分析过程,图中部分坐标标记了该坐标在数组中真实位置信息。(每个游戏的地图0,0点可能不一样,有的在左上,有的在左下,也有可能有反人类的在右边,在此我们以大话西游2经典版坐标体系为例,左下是0,0)

2、确定好地图以后,我们需要准备2个集合,一个叫做开放列表(集合list,以下称为Klist),一个叫做闭合列表(集合list,以下称为Blist)。Klist我们用来存放周边所有满足可以通过的节点,Blist我们用来存放Klist中F最小的那个值(一般来说,集合中存放的是个对象,该对象包含了该点在二维数组中的坐标信息、G值、H值、方向四种信息,不存放F是因为F=G+H)。

2.计算过程

1
1、我们获取0,0点作为起点,把它放到Klist中,然后从Klist中,取出F最小的那个值,也就是0,0点
2、拿到0,0点以后,开始获取他四周可以通过的区域,我们获取到了0,1(上方)和1,0(右侧)两个点。这两个点的F值都为7,此时我们要把{“0,1”,1,6,up}和{“1,0”,1,6,right}这两个节点的对象放到Klist中(存放顺时到Klist中,以及取最小值的顺序没有要求,在此,我们顺时针存值、倒序取值),然后吧0,0这个点放到Blist中(因为第一步从Klist中取F最小的值是0,0)。
3、我们再从Klist中取F值最小的那个对象(倒序取),发现最小的F是7,是0,1这个点。接下来我们要对0,1这个节点周边进行分析
2
1、0,1周围的节点只有up的0,2,right的1,1是黑色无法通过,所以我们不做记录。0,2节点对象信息"0,2",2,5,up存放到Klist中
2、我们倒序取F最小的那个,这次我们取出了1,0节点。并把0,1存入到了Blist中。
按照这个流程,我们最后会得到一条绿色填充的通到终点的结果集,也就是我们的Blist
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.路径回溯

通过上图,我们发现到达终点后,我们会得到一个存放了所有绿色坐标信息的Blist,此时,我们就要根据Blist中,每个对象的信息(up,left,down、right),来回溯路径,以确认真实有效的路径。

我们倒序Blist,"1,6"节点的方向信息是left,那么我们就要Blist集合中的"1+1,6"这个节点的信息,找到后。我们发现"1+1,6"节点的方向信息是left,那么我们就要在Blist中找"2+1,6"这个节点的信息,直到我们推到起点。


总结

以上就是今天要讲的内容,本文简单介绍了A星的使用。次方法的四方我们也可以扩展到8方,也就是斜对角的方格也可以计算在内,在此我们就不过多的介绍了。
代码我贴在最后:




function Aastart(mapName, ezhHeight, realMaxX, realMaxY, startX, startY, endX, endY) {
    initAstart();
    for (let a = 1; a <= ezhHeight; a++) {
        aroundList = [];
        if (mapName == "莲花洞") {
            data = file.readLine("/sdcard/Download/lianhuadong.txt", a);
        } else if (mapName == "火云洞") {
            data = file.readLine("/sdcard/Download/huoyundong.txt", a);
        } else if (mapName == "金兜洞") {
            data = file.readLine("/sdcard/Download/jindoudong.txt", a);
        } else if (mapName == "波月洞") {
            data = file.readLine("/sdcard/Download/boyuedong.txt", a);
        }

        for (let b = 0; b < data.length; b++) {
            aroundList.push(data[b])
        }
        map.push(aroundList);
    }


    startPoint = [Math.round(map[0].length / realMaxX * startX), map.length - 1 - Math.round(map.length / realMaxY * startY), 0, 0, ""] 
    finishPoint = [Math.round(map[0].length / realMaxX * endX), map.length - 1 - Math.round(map.length / realMaxY * endY), 0, 0, ""] 
    logd("X" + finishPoint[0] + "Y" + finishPoint[1]);
    if (map[finishPoint[1]][finishPoint[0]] === 1) {
        logd("finishPoint是障碍=" + 1);
    }
    openList.push(startPoint);
    logd("startPoint" + startPoint + "finishPoint" + finishPoint);
    while (true) {
        //logd("=============================================================================================");
        if (openList.length == 0 && !cmpNode(closeList, finishPoint)) {

            is_lu = false
            break
        } else {
            if (cmpNode(closeList, finishPoint)) {

                jieguo = findPath(closeList, realMaxX, realMaxY);

                is_lu = true
                break
            } else {
               
                let minF = findMinNode(openList);
                
                findNode(minF);
                
                let index = openList.indexOf(minF);
              
                openList.splice(index, 1);
              
                if (!cmpNode(closeList, minF)) {
                    closeList.push(minF);
                   
                }
            }
        }
    }
}


function findMinNode(arr) {
    let minIndex = 0;
    let minF = null;
    let F = null;
    let nodeMem = "";
    if (arr != undefined) {
        for (let a = 0; a < arr.length; a++) {
            nodeMem = arr[a].toString().split(",");
            F = parseInt(nodeMem[2]) + parseInt(nodeMem[3])

            if (minF == null || F <= minF) {

                minF = F;
                minIndex = a;
            }
        }
    }

    return arr[minIndex];
}


function findNode(minF) {

    let X = map[0].length - 1;

    let Y = map.length - 1;

    let minFX = -1;
    let minFY = -1;
    if (minF != undefined) {

        minFX = parseInt(minF.toString().split(",")[0]);

        minFY = parseInt(minF.toString().split(",")[1]);

    }
    let G = parseInt(minF.toString().split(",")[2])
  
    if ((minFY - 1) >= 0 && map[minFY - 1][minFX] == 0) {

        H = Math.abs(minFX - parseInt(finishPoint[0])) + Math.abs(minFY - 1 - parseInt(finishPoint[1]));
        node = [minFX, minFY - 1, G + 1, H, "up"];
        if (!cmpNode(closeList, node) && !cmpNode(openList, node)) {
            openList.push(node);

        }
    }
    
    //右
    if ((minFX + 1) <= X && map[minFY][minFX + 1] == 0) {

        H = Math.abs(minFX + 1 - parseInt(finishPoint[0])) + Math.abs(minFY - parseInt(finishPoint[1]));
        node = [minFX + 1, minFY, G + 1, H, "right"];
        if (!cmpNode(closeList, node) && !cmpNode(openList, node)) {
            openList.push(node);

        }
    }
    
    //下
    if ((minFY + 1) <= Y && map[minFY + 1][minFX] == 0) {

        H = Math.abs(minFX - parseInt(finishPoint[0])) + Math.abs(minFY + 1 - parseInt(finishPoint[1]));
        node = [minFX, minFY + 1, G + 1, H, "down"];
        if (!cmpNode(closeList, node) && !cmpNode(openList, node)) {
            openList.push(node);

        }
    }
   
    //左  114 38   109,72,22,39,left
    if ((minFX - 1) >= 0 && map[minFY][minFX - 1] == 0) {

        H = Math.abs(minFX - 1 - parseInt(finishPoint[0])) + Math.abs(minFY - parseInt(finishPoint[1]));
        node = [minFX - 1, minFY, G + 1, H, "left"];

        if (!cmpNode(closeList, node) && !cmpNode(openList, node)) {
            openList.push(node);

        }
    }
  
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值