【cocos creator】rpg游戏点击自动寻路移动,A*寻路,点击躲避障碍移动+相机跟随移动+相机不超过界面边界+物品显示顺序按照y坐标排列
·
AStarMove:
import AStar from "./AStar";
const { ccclass, property } = cc._decorator;
@ccclass
export default class AStarMove extends cc.Component {
@property(cc.Node)
mapNode: cc.Node = null;
@property(AStar)
aStar: AStar = null;
@property(cc.Node)
player: cc.Node = null;
@property(cc.Node)
camera: cc.Node = null;//和mapNode需要为同一父节点
start() {
this.mapNode.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
this.mapNode.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
}
onTouchEnd(event) {
this.aStar.graphicsClear();
this.aStar.drawBlock();
this.player.stopAllActions();
let oPos = event.getLocation();
let ws = this.mapNode.convertToNodeSpaceAR(oPos);
let touchPos = this.mapNode.convertToNodeSpaceAR(oPos);
touchPos.x += this.camera.x;
touchPos.y += this.camera.y;
let lastPos = this.player.position;
let startpos = this.aStar.getColRow(lastPos);
let endpos = this.aStar.getColRow(touchPos);
this.aStar.draw(startpos.x, startpos.y, cc.Color.YELLOW);
this.aStar.draw(endpos.x, endpos.y, cc.Color.GREEN);
// 开始寻路
let path = this.aStar.findPath(startpos, endpos);
if (!path) return;
let tween = cc.tween(this.player);
let speed = 600;
let moveCount = 0
for (let i = path.length - 2; i >= 0; i--) {
const element = path[i];
// let type = this.aStar.getMap(element.x, element.y)
if (element.type == -1) break;
let data = this.aStar.getMap(element.x, element.y)
if (data == -1 || data.type == -1) continue
let pos = this.aStar.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;
moveCount++
}
if (moveCount) tween.start()
}
update(dt) {
this.player.zIndex = -this.player.y + cc.winSize.height
// let scale = 2 - 1.5 * Math.abs(this.player.y + cc.winSize.height) / cc.winSize.height
// if (this.needScale) {
// this.player.scale = scale
// this.player.scaleX = this.playerScaleX * scale
// }
}
}
AStar:
const { ccclass, property } = cc._decorator;
@ccclass
export default class AStar extends cc.Component {
@property(cc.Node)
mapNode: cc.Node = null;//整个地图
@property(cc.Graphics)
mapGraphics: cc.Graphics = null;
/**障碍物根节点 */
@property(cc.Node)
itemBlockRoot: cc.Node = null;
_gridW = 50; // 单元格子宽度
_gridH = 50; // 单元格子高度
boxAngel = 30;//地图菱形,根据ui素材调整
mapH = 13; // 纵向格子数量
mapW = 25; // 横向格子数量
is8dir = true; // 是否8方向寻路
gridsList = null
onLoad() {
this.creatMap(this.mapNode, this._gridW, this._gridH)
}
creatMap(mapNode, gridW, gridH) {
const manager = cc.director.getCollisionManager();
manager.enabled = true;
manager.enabledDebugDraw = true;
manager.enabledDrawBoundingBox = true;
this.mapH = Math.round(mapNode.height / gridH);
this.mapW = Math.round(mapNode.width / gridW);
this.initMap();
this.initBlock()
}
graphicsClear() {
this.mapGraphics.clear()
}
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.mapNode.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()
}
getMap(i, j) {
if (!this.gridsList || !this.gridsList[i] || !cc.isValid(this.gridsList[i][j])) return -1
return this.gridsList[i][j]
}
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.mapGraphics.clear();
for (let col = 0; col <= this.mapW; col++) {
for (let row = 0; row <= this.mapH; row++) {
this.addGrid(col, row, 0);
}
}
cc.log(this.gridsList)
}
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] == -1) {
this.draw(col, row, cc.Color.RED);
}
}
}
}
addBlock(newPos) {
const { x, y } = newPos;
if (!this.gridsList[x] || !cc.isValid(this.gridsList[x][y])) return
if (this.gridsList[x][y] == 0) {
this.gridsList[x][y] = -1;
}
}
checkBlock(newPos) {
const { x, y } = newPos;
if (!this.gridsList[x] || !cc.isValid(this.gridsList[x][y])) return
return this.gridsList[x][y] == -1
}
addGrid(x, y, type) {
// -1障碍物, 0正常, 1起点, 2目的点
this.gridsList[x][y] = type;
}
_sortFunc(x, y) {
let a = x.f || 0
let b = y.f || 0
return a - b;
}
generatePath(grid) {
let path = []
path.push(grid);
while (grid.parent) {
grid = grid.parent;
path.push(grid);
}
cc.log("path.length: " + path.length, path);
for (let i = 0; i < path.length; i++) {
// 起点终点不覆盖,方便看效果
let grid = path[i];
if (i == 0) {
this.draw(grid.x, grid.y, cc.Color.ORANGE);
}
else if (i == path.length - 1) {
this.draw(grid.x, grid.y, cc.Color.BLUE);
}
else {
this.draw(grid.x, grid.y, cc.Color.GREEN);
}
}
return path;
}
findPath(startPos, endPos, gridsArr = this.gridsList) {
let openList = [];
let closeList = [];
let gridsList = this.crearArr(gridsArr)
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);
}
this.findPathCorrect(curGrid, gridsList, closeList, endPos, openList, this.is8dir)
// 遍历完四周节点后把当前节点加入关闭列表
closeList.push(curGrid);
// 从开放列表把当前节点移除
openList.splice(openList.indexOf(curGrid), 1);
if (openList.length <= 0) {
cc.log("find path failed.");
break;
}
// 重新按照f值排序(升序排列)
openList.sort(this._sortFunc);
}
//无视障碍查找
openList = [];
closeList = [];
gridsList = this.crearArr(gridsArr)
openList.push(startGrid);
startGrid = gridsList[startPos.x][startPos.y];
endGrid = gridsList[endPos.x][endPos.y];
endGrid.type = 2;
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);
}
this.findPathCorrect(curGrid, gridsList, closeList, endPos, openList, false, false)
// 遍历完四周节点后把当前节点加入关闭列表
closeList.push(curGrid);
// 从开放列表把当前节点移除
openList.splice(openList.indexOf(curGrid), 1);
if (openList.length <= 0) {
cc.log("find path failed.");
break;
}
// 重新按照f值排序(升序排列)
openList.sort(this._sortFunc);
}
return false;
}
crearArr(gridsArr) {
let gridsList = []
for (let i = 0; i < gridsArr.length; i++) {
gridsList[i] = [];
for (let j = 0; j < gridsArr[i].length; j++) {
let grid = {
x: i,
y: j,
type: (gridsArr[i][j] + "")// -1障碍物, 0正常, 1起点, 2目的点
}
gridsList[i][j] = grid
}
}
return gridsList
}
findHave(data, list) {
let index = list.findIndex((value) => { return value.x == data.x && data.y == value.y })
return index == -1
}
findPathCorrect(curGrid, gridsList, closeList, endPos, openList, is8dir = true, checkBlock = true) {
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
&& (!checkBlock || (checkBlock && gridsList[col][row].type != -1))
&& this.findHave(gridsList[col][row], closeList)) {
if (is8dir) {
// 8方向 斜向走动时要考虑相邻的是不是障碍物
if (gridsList[col - i][row].type == -1 || gridsList[col][row - j].type == -1) {
if (checkBlock) continue;
}
} else {
// 四方形行走
if (Math.abs(i) == Math.abs(j)) {
continue;
}
}
let g = curGrid.g || 0
// 计算g值
g = g + Math.sqrt(Math.pow(i * 10, 2) + Math.pow(j * 10, 2));
if (gridsList[col][row].type == -1) {
g += 100;//如果是不可走,排位放后
}
if (!gridsList[col][row].g || 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);
if (gridsList[col][row].type == -1) {
gridsList[col][row].h += 100;//如果是不可走,排位放后
}
// 更新f值
gridsList[col][row].f = gridsList[col][row].g + gridsList[col][row].h;
// 如果不在开放列表里则添加到开放列表里
if (this.findHave(gridsList[col][row], openList)) {
openList.push(gridsList[col][row]);
}
// // 重新按照f值排序(升序排列)
// openList.sort(this._sortFunc);
}
}
}
}
}
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, a = 100) {
this.mapGraphics.strokeColor = color;
this.mapGraphics.strokeColor.a = a;//添加透明度
let pos1 = this.getPos(start_col_cow)
let pos2 = this.getPos(end_col_cow)
this.mapGraphics.lineWidth = width;
this.mapGraphics.moveTo(pos1.x, pos1.y);
this.mapGraphics.lineTo(pos2.x, pos2.y);
this.mapGraphics.stroke();
}
draw(col, row, color = new cc.Color().fromHEX("#FF000033"), a = 100) {
this.mapGraphics.fillColor = color;
this.mapGraphics.fillColor.a = a;//添加透明度
let pos = this.getPos(cc.v2(col, row))
this.mapGraphics.fillRect(pos.x, pos.y, this._gridW, this._gridH);
}
}
SceneCtrl2D
const { ccclass, property } = cc._decorator;
@ccclass
export default class SceneCtrl2D extends cc.Component {
@property(cc.Node)
moveSide: cc.Node = null;
@property(cc.Node)
player: cc.Node = null;
@property(cc.Camera)
camera: cc.Camera = null;
@property(cc.Node)
itemRoot: cc.Node = null;
onLoad() {
}
start() {
let ws = this.player.convertToWorldSpaceAR(cc.v2(0, 0))
let pos = this.moveSide.parent.convertToNodeSpaceAR(ws)
this.scheduleOnce(() => {
this.camera.node.setPosition(pos);
})
this.itemRoot.children.forEach(element => {
element.zIndex = -element.y + cc.winSize.height
});
}
lateUpdate(dt) {
let ws = this.player.convertToWorldSpaceAR(cc.v2(0, 0))
let pos = this.moveSide.parent.convertToNodeSpaceAR(ws)
// let dis = pos.sub(cc.v2(this.moveSide.position)).mag()
let disX = cc.v2(pos.x, 0).sub(cc.v2(this.moveSide.position.x, 0)).mag()
let disY = cc.v2(pos.y, 0).sub(cc.v2(this.moveSide.position.y, 0)).mag()
if (pos.x <= this.moveSide.x - this.moveSide.width / 2 + cc.winSize.width / 2) {
pos.x = this.moveSide.x - this.moveSide.width / 2 + cc.winSize.width / 2
this.camera.node.x = pos.x;
}
else if (pos.x >= this.moveSide.x + this.moveSide.width / 2 - cc.winSize.width / 2) {
pos.x = this.moveSide.x + this.moveSide.width / 2 - cc.winSize.width / 2
this.camera.node.x = pos.x;
}
else {
this.camera.node.x = pos.x;
if (disX < 1) {
this.camera.node.x = pos.x;
}
else if (this.camera.node.x < pos.x) {
this.camera.node.x += Math.max(1, 10 / disX)
}
else {
this.camera.node.x -= Math.max(1, 10 / disX)
}
}
if (pos.y <= this.moveSide.y - this.moveSide.height / 2 + cc.winSize.height / 2) {
pos.y = this.moveSide.y - this.moveSide.height / 2 + cc.winSize.height / 2
this.camera.node.y = pos.y;
}
else if (pos.y >= this.moveSide.y + this.moveSide.height / 2 - cc.winSize.height / 2) {
pos.y = this.moveSide.y + this.moveSide.height / 2 - cc.winSize.height / 2
this.camera.node.y = pos.y;
}
else {
this.camera.node.y = pos.y;
if (disY < 1) {
this.camera.node.y = pos.y;
}
else if (this.camera.node.y < pos.y) {
this.camera.node.y += Math.max(1, 10 / disY)
}
else {
this.camera.node.y -= Math.max(1, 10 / disY)
}
}
}
}
更多推荐

所有评论(0)