CocosCreator之KUOKUO趣味文章:小怪会A星寻路 5

引擎版本 v2.0.10

小怪的思考

在上一篇文章中,小怪采用了包围盒子边界检测的方法实现了寻路。但是狡猾的玩家对此采取了措施。他偷偷的加固了防线!

在这里插入图片描述

这可难坏了小怪。

哼,玩家一定是想消耗我的体力,让我像无头苍蝇般乱走,我才不上当呢!
于是我拿出了 KUOKUO 大人赏的纸和笔,开始思考!

我需要两个列表(数组):
一个记录下所有被考虑来寻找最近的点集合
一个记录下不会再被考虑的点集合

// 一个点上应该具有的属性
let obj = new Object();
obj.x = ...
obj.y = ... 
// g 随着离开始点越来越远而增大
obj.g = ...
// h 当前点到目标点的移动量估算值
obj.h = ...
obj.f = ...
obj.parent = ...

根据 f 值寻路后可依靠 parent 回溯

// ......
 	this.final = [];
    while(p) {
        this.final.push(p);
        p = p.parent;
    }
    // 翻转
    this.final.reverse();
    // 沿着 final 走
// ......

这样虽然多思考了几个路径上的点,但是我思考后可直接行走。

试试?试试!
在这里插入图片描述

哼哼!愚蠢的人类。

完整代码

cc.Class({
    extends: cc.Component,

    properties: {
        // 小怪
        me : cc.Node
    },

    onLoad () {
        // 地图数据,0是地板,1是墙
        this.map = [
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 1, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
        ];
        this.open = [];
        this.close = [];
    },

    start () {
        // 小怪的坐标
        this.mIndex = cc.v2(4, 0);
        // 玩家坐标点
        this.pIndex = cc.v2(3, 9);
        // 开始
        this.aStar();
    },

    aStar () {
        // 限制次数 500;
        // 首先将小怪的位置装入 close 列表
        let time = 500;
        let obj = new Object();
        obj.x = this.mIndex.x;
        obj.y = this.mIndex.y;
        obj.g = this.manHattan(this.mIndex, this.mIndex);
        obj.h = this.manHattan(this.mIndex, this.pIndex);
        obj.f = obj.g + obj.h;
        obj.parent = null;
        this.pushInClose(obj);
        let temp = obj;
        while (true) {
            time--;
            // 周围一圈装入 open
            this.aroundPos(temp);
            // 在 open 中找到 f 最小的,装入 close 并返回该点;
            temp = this.findMinInOpen();
            if (temp.x == this.pIndex.x && temp.y == this.pIndex.y) {
                break;
            }
            if (time <= 0) {
                console.log('寻找不到');
                break;
            }
        }
        // 根据 parent 最终确认路线
        let l = this.close.length - 1;
        let p = this.close[l];
        this.final = [];
        while(p) {
            this.final.push(p);
            p = p.parent;
        }
        // 翻转
        this.final.reverse();
        // 沿着 final 走
        this.go(0);
    },

    go (i) {
        this.me.runAction(cc.sequence(
            cc.moveTo(0.5,this.convertToPoints(this.final[i].x, this.final[i].y)),
            cc.callFunc(() => {
                if (i == this.final.length - 1) return;
                i++;
                this.go(i);
            },this)
        ));
    },

    findMinInOpen () {
        let min = 999;
        let index = null;
        for (let i = 0; i < this.open.length; i++) {
            if (this.open[i].f <= min) {
                min = this.open[i].f;
                index = i;
            }
        }
        let obj = this.open.splice(index, 1);
        this.pushInClose(obj[0]);
        return obj[0];
    },

    aroundPos (parent) {
        let dir = [[0,1],[1,0],[0,-1],[-1,0]];
        for (let i = 0; i < 4;i++) {
            let mx = parent.x + dir[i][0];
            let my = parent.y + dir[i][1];
            // 是否出界
            if (mx < 0 || mx > 6 || my < 0 || my > 9) {
                continue;
            }
            // 是否为墙
            if (this.map[mx][my] == 1) {
                continue;
            }
            // 是否已经在 close 中了
            if (this.isInClose(mx, my)) {
                continue;
            }
            // 是否已经在 open 中了
            if (this.isInOpen(mx, my)) {
                continue;
            }
            // 装入 open
            this.pushInOpen(cc.v2(mx, my), parent);
        }
    },

    isInOpen (mx, my) {
        for (let i = 0; i < this.open.length; i++) {
            if (this.open[i].x == mx && this.open[i].y == my) {
                return true;
            }
        }
        return false;
    },

    isInClose (mx, my) {
        for (let i = 0; i < this.close.length; i++) {
            if (this.close[i].x == mx && this.close[i].y == my) {
                return true;
            }
        }
        return false;
    },

    pushInOpen (v, parent) {
        let obj = new Object();
        obj.x = v.x;
        obj.y = v.y;
        obj.g = this.manHattan(v, this.mIndex);
        obj.h = this.manHattan(v, this.pIndex);
        obj.f = obj.g + obj.h;
        obj.parent = parent;
        this.open.push(obj);
    },

    pushInClose (obj) {
        this.close.push(obj);
    },

    // 转化坐标
    convertToPoints (dx, dy) {
        let y = 300 - 100 * dx;
        let x = 100 * dy - 450;
        return cc.v2(x, y);
    },

    // 曼哈顿估价法,传入当前点与目标点,返回估值
    manHattan (nowPoint, pIndex) {
        let dx = Math.abs(nowPoint.x - pIndex.x);
        let dy = Math.abs(nowPoint.y - pIndex.y);
        return dx + dy;
    }

});

O(∩_∩)O~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KUOKUO众享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值