地图编辑器开发(三)

上一节已经把地图信息编辑做好了,这一节实现对编辑好的地图信息进行测试。主要实现以下功能:

  1. A星寻路
  2. 显示路径
  3. 角色移动

A星寻路

A星寻路算法的基本概念,参考维基百科,算法核心有以下几个点:

  • 开放列表和关闭列表
  • 按 f 值排序
  • 回溯路径

推荐一个视频教程,概念,算法过程,实现都讲得非常详细。

A星寻路算法最终要实现的是,传入地图信息,起点和终点,得到一个从起点到终点的路径,即从起点到终点所经过的格子列表。核心代码如下:

 // 把起点放入开启列表中
 this.openList.push(this.fromNode);

 let cur;
 while(true) {
     // 从开启列表中取出消耗最少的节点(已拍下,取最后一个节点)
     cur = this.openList.pop();

     // 如果是终点,则返回路径
     if (cur === this.toNode) {
         let pathList = [];
         pathList.push(cur);
         let end = cur;
         while(end.last) {
             pathList.unshift(end.last);
             end = end.last;
         }
         return pathList;
     } else {
         // 不是终点,则加入到关闭列表中
         this.closeList.push(cur);
     }

     // 将当前点周围的点,放入开启列表
     this.searchRound(cur);

     // 死路判断
     if (this.openList.length === 0) {
         return;
     }

     // 排序,保证最后一个消耗最少
     this.openList.sort((a, b) => {
         return b.f - a.f;
     });
 }

显示路径

使用A星寻路找出路径之后,把找出的路径显示出来,便于观察。显示路径的方法是把找出的格子画成绿色。主要代码如下:

drawPath() {
	let node;
	for (let i = 0; i < this.pathList.length; i++) {
	    let node = this.pathList[i];
	    this.gphPath.rect(node.x * this.cellW, node.y * this.cellH, this.cellW, this.cellH);
	    this.gphPath.fillColor = this.colorPath;
	    this.gphPath.fill();
	}
},

运行结果:
地图编辑器开发(三)_第1张图片

角色移动

为了方便设置起点和终点,添加一个图标作为游戏玩家,拖动游戏玩家设置寻路的起点,之后鼠标点击的位置,作为寻路的终点。另外在在工具栏加一个测试按钮,区分测试和正常编辑这两个状态。
地图编辑器开发(三)_第2张图片
还是不够直观,再把角色移动的路径也画出来,代码如下:

void drawTrack() {
    this.gphPath.strokeColor = this.colorPathLine;
    this.gphPath.lineWidth = 5;
    let pre;
    for (let i = 1; i < this.pathList.length; i++) {
        pre = this.pathList[i - 1];
        this.gphPath.moveTo ((pre.x + 0.5) * this.cellW, (pre.y + 0.5) * this.cellH)
        node = this.pathList[i];
        this.gphPath.lineTo ((node.x + 0.5) * this.cellW, (node.y + 0.5) * this.cellH);
    }
}

这样就能直观的看到角色移动时所经过的格子和行动的轨迹。
地图编辑器开发(三)_第3张图片
辅助工具都有了,最后就是让角色移动起来,为了简单直接使用 cocos creator 提供的动画来实现。给角色挂上一个脚本,将寻路算法返回的路径列表传递给该脚本,然后实现一个移动到指点格子的方法,逐个将路径中的点传递给该方法。

runToNext() {
    this.srcNode = this.pathList[this.toIndex];
    this.toIndex += 1;
    this.dstNode = this.pathList[this.toIndex];
    let node = this.pathList[this.toIndex];
    if (node) {
        this.runTo((node.x + 0.5) * this.cellW, (node.y + 0.5) * this.cellH);
    }
},
    
runTo(x, y){
    // 移动方向
    let dir = [this.dstNode.x - this.srcNode.x, this.dstNode.y - this.srcNode.y];
    let rad = Math.atan2(dir[1], dir[0]);
    let angle = 180/Math.PI * rad;
    this.node.angle = angle;

    // 移动时间
    tm = 0.2;
    if (this.srcNode.x !== this.dstNode.x && this.srcNode.y !== this.dstNode.y) {
        // 斜方向移动距离更长,时间要长一点
        tm *= 1.4;
    }
    cc.tween(this.node)
        .to(tm, {position: cc.v2(x, y)})
        .call(() => {this.runToNext()})
        .start()
},

其中两个小点要注意:

  • 斜方向移动时,距离相交竖直和水平移动更长,因此动画时间要放大一点;
  • 角色朝向设置,在角色节点上加了一个小方块表示角色正面,根据移动方向设置角色朝向。

角色移动的过程如下:
地图编辑器开发(三)_第4张图片
测试这一块到这里就差不多了,下一节再看导出地图数据。

你可能感兴趣的:(游戏开发,开发工具)