项目下载
https://download.csdn.net/download/K86338236/89529461
根据多边形碰撞体范围划定障碍范围,躲避障碍,点击屏幕移动,每次点击更新寻路路径 移动用tween实现
const { ccclass, property } = cc._decorator;
@ccclass
export default class AStar extends cc.Component {
@property(cc.Graphics)
map: cc.Graphics = null;
@property(cc.Node)
item: cc.Node = null;
@property(cc.Node)
itemBlockRoot: cc.Node = null;
_gridW = 50; // 单元格子宽度
_gridH = 50; // 单元格子高度
mapH = 13; // 纵向格子数量
mapW = 25; // 横向格子数量
is8dir = true; // 是否8方向寻路
gridsList = null
onLoad() {
const manager = cc.director.getCollisionManager();
manager.enabled = true;
manager.enabledDebugDraw = true;
manager.enabledDrawBoundingBox = true;
this.mapH = Math.round(cc.winSize.height / this._gridH);
this.mapW = Math.round(cc.winSize.width / this._gridW);
this.initMap();
this.initBlock()
this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchMove, this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
}
initBlock() {
this.itemBlockRoot.children.forEach((value) => {
let collider = value.getComponent(cc.PolygonCollider)
if (!collider) return
let points = collider.points;
for (let col = 0; col <= this.mapW; col++) {
for (let row = 0; row <= this.mapH; row++) {
let oPos = this.getPos(cc.v2(col + 0.5, row + 0.5))
let w_pos = this.node.convertToWorldSpaceAR(oPos);
let pos = value.convertToNodeSpaceAR(w_pos);
let isIn = cc.Intersection.pointInPolygon(cc.v2(pos), points)
if (isIn) {
this.addBlock(cc.v2(col, row))
}
}
}
})
this.drawBlock()
}
initMap() {
// 初始化格子二维数组
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.addGrid(col, row, 0);
}
}
}
drawBlock() {
for (let col = 0; col <= this.mapW + 1; col++) {
this.drawLine(cc.v2(col, 0), cc.v2(col, this.mapH + 1));
}
for (let row = 0; row <= this.mapH + 1; row++) {
this.drawLine(cc.v2(0, row), cc.v2(this.mapW + 1, row));
}
for (let col = 0; col <= this.mapW; col++) {
for (let row = 0; row <= this.mapH; row++) {
if (this.gridsList[col][row].type == -1) {
this.draw(col, row, cc.Color.RED);
}
}
}
}
addBlock(newPos) {
const { x, y } = newPos;
if (!this.gridsList[x] || !this.gridsList[x][y]) return
if (this.gridsList[x][y].type == 0) {
this.gridsList[x][y].type = -1;
}
}
onTouchMove(event) {
return
let oPos = event.getLocation();
let pos = this.map.node.convertToNodeSpaceAR(oPos)
let newPos = this.getColRow(pos)
const { x, y } = newPos;
if (!this.gridsList[x] || !this.gridsList[x][y]) return
if (this.gridsList[x][y].type == 0) {
this.gridsList[x][y].type = -1;
this.draw(x, y, cc.Color.RED);
}
cc.log(x + "," + y);
}
onTouchEnd(event) {
this.map.clear();
this.drawBlock()
this.item.stopAllActions();
let oPos = event.getLocation();
let touchPos = this.map.node.convertToNodeSpaceAR(oPos)
let lastPos = this.item.position;
let startpos = this.getColRow(lastPos)
let endpos = this.getColRow(touchPos)
this.draw(startpos.x, startpos.y, cc.Color.YELLOW);
this.draw(endpos.x, endpos.y, cc.Color.GREEN);
// 开始寻路
let path = this.findPath(startpos, endpos);
if (!path) return
let tween = cc.tween(this.item)
let speed = 300;
for (let i = path.length - 2; i >= 0; i--) {
const element = path[i];
let pos = this.getPos(cc.v2(element.x + 0.5, element.y + 0.5))
let dis = lastPos.sub(pos).mag()
let t = dis / speed;
let tween2 = cc.tween().to(t, { position: pos })
tween.then(tween2)
lastPos = pos;
}
tween.start()
}
addGrid(x, y, type) {
let grid = {
x: 0,
y: 0,
f: 0,
g: 0,
h: 0,
parent: null,
type: 0 // -1障碍物, 0正常, 1起点, 2目的点
}
grid.x = x;
grid.y = y;
grid.type = type;
this.gridsList[x][y] = grid;
}
_sortFunc(x, y) {
return x.f - y.f;
}
generatePath(grid) {
let path = []
path.push(grid);
while (grid.parent) {
grid = grid.parent;
path.push(grid);
}
cc.log("path.length: " + path.length);
for (let i = 0; i < path.length; i++) {
// 起点终点不覆盖,方便看效果
if (i != 0 && i != path.length - 1) {
let grid = path[i];
this.draw(grid.x, grid.y, cc.Color.GREEN);
}
}
return path;
}
findPath(startPos, endPos) {
let openList = [];
let closeList = [];
let gridsList = JSON.parse(JSON.stringify(this.gridsList))
let startGrid = gridsList[startPos.x][startPos.y];
let endGrid = gridsList[endPos.x][endPos.y];
endGrid.type = 2;
openList.push(startGrid);
let curGrid = openList[0];
while (openList.length > 0 && curGrid.type != 2) {
// 每次都取出f值最小的节点进行查找
curGrid = openList[0];
if (curGrid.type == 2) {
cc.log("find path success.");
endGrid.type = 0;
return this.generatePath(curGrid);
}
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
&& gridsList[col][row].type != -1
&& closeList.indexOf(gridsList[col][row]) < 0) {
if (this.is8dir) {
// 8方向 斜向走动时要考虑相邻的是不是障碍物
if (gridsList[col - i][row].type == -1 || gridsList[col][row - j].type == -1) {
continue;
}
} else {
// 四方形行走
if (Math.abs(i) == Math.abs(j)) {
continue;
}
}
// 计算g值
let g = curGrid.g + Math.sqrt(Math.pow(i * 10, 2) + Math.pow(j * 10, 2));
if (gridsList[col][row].g == 0 || gridsList[col][row].g > g) {
gridsList[col][row].g = g;
// 更新父节点
gridsList[col][row].parent = curGrid;
}
// 计算h值 manhattan估算法
gridsList[col][row].h = Math.abs(endPos.x - col) + Math.abs(endPos.y - row);
// 更新f值
gridsList[col][row].f = gridsList[col][row].g + gridsList[col][row].h;
// 如果不在开放列表里则添加到开放列表里
if (openList.indexOf(gridsList[col][row]) < 0) {
openList.push(gridsList[col][row]);
}
// // 重新按照f值排序(升序排列)
// openList.sort(this._sortFunc);
}
}
}
}
// 遍历完四周节点后把当前节点加入关闭列表
closeList.push(curGrid);
// 从开放列表把当前节点移除
openList.splice(openList.indexOf(curGrid), 1);
if (openList.length <= 0) {
cc.log("find path failed.");
}
// 重新按照f值排序(升序排列)
openList.sort(this._sortFunc);
}
return false;
}
getPos(pos) {
const { x, y } = pos
let posX = (x - this.mapW / 2) * (this._gridW);
let posY = (y - this.mapH / 2) * (this._gridH);
return cc.v3(posX, posY)
}
getColRow(pos) {
let x = Math.floor(pos.x / (this._gridW) + this.mapW / 2);
let y = Math.floor(pos.y / (this._gridH) + this.mapH / 2);
return cc.v3(x, y)
}
drawLine(start_col_cow, end_col_cow, color = cc.Color.GRAY, width = 4) {
this.map.strokeColor = color;
this.map.strokeColor.a = 10;//添加透明度
let pos1 = this.getPos(start_col_cow)
let pos2 = this.getPos(end_col_cow)
this.map.lineWidth = width;
this.map.moveTo(pos1.x, pos1.y);
this.map.lineTo(pos2.x, pos2.y);
this.map.stroke();
}
draw(col, row, color = new cc.Color().fromHEX("#FF000033")) {
this.map.fillColor = color;
this.map.fillColor.a = 20;//添加透明度
let pos = this.getPos(cc.v2(col, row))
this.map.fillRect(pos.x, pos.y, this._gridW, this._gridH);
}
}