【cocos】A*寻路,移动
程序员文章站
2024-03-25 20:00:22
...
挂在要移动的物体上
//AStar.js
// Learn cc.Class:
// - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/class.html
// - [English] http://www.cocos2d-x.org/docs/creator/en/scripting/class.html
// Learn Attribute:
// - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/reference/attributes.html
// - [English] http://www.cocos2d-x.org/docs/creator/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
// - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html
// - [English] http://www.cocos2d-x.org/docs/creator/en/scripting/life-cycle-callbacks.html
let Grid = cc.Class({
ctor() {
this.x = 0;
this.y = 0;
this.f = 0;
this.g = 0;
this.h = 0;
this.parent = null;
this.type = 0; // -1障碍物, 0正常, 1起点, 2目的点
}
});
let AStar = cc.Class({
extends: cc.Component,
properties: {
is8dir: false, // 是否8方向寻路
map: cc.Graphics,
},
statics: {
_instance: null,
Instance() {
return AStar._instance;
},
},
onLoad() {
this.timer = 0;
this.timeron = true;
//this.map = cc.find("Canvas/map").getComponent(cc.Graphics);
this.curGrid = [];
this.curGridmin = [];
this.startX = 0;
this.startY = 0;
this.endX = 0;
this.endY = 0;
AStar._instance = this;
this._gridW = 50; // 单元格子宽度
this._gridH = 50; // 单元格子高度
this.mapH = 50; // 纵向格子数量
this.mapW = 100; // 横向格子数量
this.index = 0;
cc.find("Canvas").on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
cc.find("Canvas").on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
cc.find("Canvas").on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
this.initMap();
this.touch = false;
},
start() {
let pos = this.node;
this.startX = Math.floor(pos.x / (this._gridW));
this.startY = Math.floor(pos.y / (this._gridH));
this.node.x = this.startX * (this._gridW);
},
onTouchStart(event) {
let pos1 = this.node;
this.startX = Math.floor(pos1.x / (this._gridW));
this.startY = Math.floor(pos1.y / (this._gridH));
let pos = event.getLocation();
let x = Math.floor(pos.x / (this._gridW));
let y = Math.floor(pos.y / (this._gridH));
this.unschedule(this.move, 0.35, this.path.length);
this.endX = x;
this.endY = y;
this.startFind();
this.generatePath(this.curGridmin);
this.touch = true;
this.node.stopAllActions();
//移动
//cc.log(this.path.length);
this.index = this.path.length - 2;
//cc.log("***********");
this.schedule(this.move, 0.35, this.path.length);
},
onTouchMove(event) {
let pos = event.getLocation();
let x = Math.floor(pos.x / (this._gridW));
let y = Math.floor(pos.y / (this._gridH));
},
setMap: function () {
var cfg = [];
//障碍物
var cfg = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
];
for (var i = 0; i < cfg.length; i++) {
for (var j = 0; j < cfg[i].length; j++) {
if (cfg[i][j] === 1) {
this.gridsList[j][this.mapH - i - 1].type = -1;
this.draw(j, this.mapH - i - 1, cc.Color.RED);
}
}
}
},
onTouchEnd() {
this.touch = false;
},
startFind() {
// 开始寻路
this.initMap();
this.findPath(cc.v2(this.startX, this.startY), cc.v2(this.endX, this.endY));
},
initMap() {
this.openList = [];
this.closeList = [];
this.path = [];
// 初始化格子二维数组
this.gridsList = new Array(this.mapW + 1);
for (let col = 0; col < this.gridsList.length; col++) {
this.gridsList[col] = new Array(this.mapH + 1);
}
this.map.clear();
for (let col = 0; col <= this.mapW; col++) {
for (let row = 0; row <= this.mapH; row++) {
this.draw(col, row);
this.addGrid(col, row, 0);
}
}
//this.setMap();
// 设置起点和终点
let startX = this.startX;
let startY = this.startY;
let endX = this.endX;
let endY = this.endY;
cc.log(this.endX + " " + this.endY);
if (this.endX <= 0 || this.endX > this.mapW || this.endY <= 0 || this.endY > this.mapH) {
return;
}
this.gridsList[startX][startY].type = 1;
this.draw(this.startX, this.startY, cc.Color.YELLOW);
this.gridsList[endX][endY].type = 2;
this.draw(this.endX, this.endY, cc.Color.BLUE);
},
addGrid(x, y, type) {
let grid = new Grid();
grid.x = x;
grid.y = y;
grid.type = type;
this.gridsList[x][y] = grid;
},
_sortFunc(x, y) {
return x.f - y.f;
},
generatePath(grid) {
this.path.push(grid);
while (grid.parent) {
grid = grid.parent;
this.path.push(grid);
}
//cc.log("path.length: " + this.path.length);
//cc.log("***********");
for (let i = 0; i < this.path.length; i++) {
// 起点终点不覆盖,方便看效果
if (i != 0 && i != this.path.length - 1) {
let grid = this.path[i];
this.draw(grid.x, grid.y, cc.Color.GREEN);
//cc.log(grid.x + " " + grid.y);
}
}
//cc.log(this.path.length);
},
move: function () {
if (this.index >= 0 && this.index != this.path.length) {
let grid = this.path[this.index];
this.node.x = grid.x * (this._gridW + 2) + this._gridW / 2;
this.node.y = grid.y * (this._gridH + 2) + this._gridH / 2;
this.index--;
}
},
findPath(startPos, endPos) {
let startGrid = this.gridsList[startPos.x][startPos.y];
let endGrid = this.gridsList[endPos.x][endPos.y];
this.openList.push(startGrid);
let curGrid = this.openList[0];
while (this.openList.length > 0 && curGrid.type != 2) {
// 每次都取出f值最小的节点进行查找
curGrid = this.openList[0];
if (curGrid.type == 2) {
cc.log("find path success.");
this.generatePath(curGrid);
return;
}
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
if (i != 0 || j != 0) {
let col = curGrid.x + i;
let row = curGrid.y + j;
if (col >= 0 && row >= 0 && col <= this.mapW && row <= this.mapH
&& this.gridsList[col][row].type != -1
&& this.closeList.indexOf(this.gridsList[col][row]) < 0) {
if (this.is8dir) {
// 8方向 斜向走动时要考虑相邻的是不是障碍物
if (this.gridsList[col - i][row].type == -1 || this.gridsList[col][row - j].type == -1) {
continue;
}
} else {
// 四方形行走
if (Math.abs(i) == Math.abs(j)) {
continue;
}
}
// 计算g值
let g = curGrid.g + parseInt(Math.sqrt(Math.pow(i * 10, 2) + Math.pow(j * 10, 2)));
if (this.gridsList[col][row].g == 0 || this.gridsList[col][row].g > g) {
this.gridsList[col][row].g = g;
// 更新父节点
this.gridsList[col][row].parent = curGrid;
}
// 计算h值 manhattan估算法
this.gridsList[col][row].h = Math.abs(endPos.x - col) + Math.abs(endPos.y - row);
// 更新f值
this.gridsList[col][row].f = this.gridsList[col][row].g + this.gridsList[col][row].h;
// 如果不在开放列表里则添加到开放列表里
if (this.openList.indexOf(this.gridsList[col][row]) < 0) {
this.openList.push(this.gridsList[col][row]);
}
// // 重新按照f值排序(升序排列)
// this.openList.sort(this._sortFunc);
}
}
}
}
// 遍历完四周节点后把当前节点加入关闭列表
this.closeList.push(curGrid);
// 从开放列表把当前节点移除
this.openList.splice(this.openList.indexOf(curGrid), 1);
if (this.openList.length <= 0) {
cc.log("find path failed.");
}
// 重新按照f值排序(升序排列)
this.openList.sort(this._sortFunc);
}
},
//画颜色
draw(col, row, color) {
color = color != undefined ? color : cc.Color.GRAY;
this.map.fillColor = color;
let posX = 2 + col * (this._gridW + 2);
let posY = 2 + row * (this._gridH + 2);
this.map.fillRect(posX, posY, this._gridW, this._gridH);
}
});
链接:https://pan.baidu.com/s/1fdXgPvqw5JTsPN7XYZ99qw
提取码:x1ze
复制这段内容后打开百度网盘手机App,操作更方便哦