系列教程:
上一节已经把地图加载到游戏中了,这一节主要实现地图的编辑能功能,也是地图编辑器最主要的功能,可以拆分为如下几个功能:
- 地图滚动
- 地图缩放
- 画网格
- 编辑格子信息
地图滚动
上一节中加载进来的地图,只显示了地图的一部分,要能编辑整个地图,需要地图能够滚动。因此需要将地图 sprite 放入到一个 ScrollView 中,设置水平和竖直方向都能滚动,删除滚动条,防止挡住地图,如图:
运行结果如下图:
这样地图就滚动了,按住鼠标就能拖动地图。但是还有问题,窗口显示的范围并没有变大,希望能通过缩放,在窗口中显示更多的内容。
地图缩放
在工具栏上,放一个滑块,用于控制地图的缩放比例。监听滑块值变化,在响应函数中,调整地图的宽高。
实现效果如上图所示,核心代码如下:
onScaleChange(slider) {
this.mapScale = slider.progress;
// 显示地图宽高
this.mapW = this.oriW * this.mapScale;
this.mapH = this.oriH * this.mapScale;
this.ndSvContent.width = this.mapW;
this.ndSvContent.height = this.mapH;
},
画网格
A星寻路都是以格子为单位,因此需要将地图划分成很多小格子,然后才能编辑每个格子的数据。Cocos Creator 提供了一个 画图组件,就用这个组件来画网格。在编辑器中,创建一个 Graphic组件,作为地图spMap的子节点,这样格子才会随着地图一起缩放和移动。
为了方便查看,让格子和地图都可以隐藏和显示,在界面上加上复选框。另外,在设置界面中,可以设置格子的大小。做好之后如图:
ui都编辑好之后,就可以写代码实现画格子了。
drawGrid() {
this.gphPath.strokeColor = this.colorGrid;
this.gphPath.lineWidth = 1;
let cnt_w = Math.floor(this.mapW / this.cellW);
for (let i = 1; i < cnt_w; i++) {
let x = this.cellW * i;
this.gphPath.moveTo (x, 0)
this.gphPath.lineTo (x, this.mapH);
}
let cnt_h = Math.floor(this.mapH / this.cellH);
for (let i = 0; i < cnt_h; i++) {
let y = this.cellH * i;
this.gphPath.moveTo (0, y)
this.gphPath.lineTo (this.mapW, y);
}
this.gphPath.stroke();
},
运行可以看到地图已经被划分成了很多小格子,如图:
编辑格子
格子划分好之后,以格子为单位编辑,可以将格子设置阻挡状态,遮罩状态,或者删除已设置的状态,除此之外,鼠标还要完成拖动操作。根据前面的分析,将鼠标分为4种状态,这4种状态是不可以叠加的,可以使用单选框来实现,当修改单选框的值时,更新鼠标的状态。如图:
- 当鼠标状态处于拖动状态时,将 ScrollView 设置为可以滚动,其他状态禁止滚动,避免编辑格子时,地图跟着滚动。
- 当鼠标处理其他阻挡状态时,获取鼠标所在的格子,然后其状态改为阻挡状态,用红色表示;
- 当鼠标处理其他遮罩状态时,获取鼠标所在的格子,然后其状态改为遮罩状态,用蓝色表示;
- 当鼠标处理其他清除状态时,获取鼠标所在的格子,然后其状态改为默认状态;
- 最后根据格子的状态信息,绘制阻挡和遮罩。
用代码实现上述过程:
onLoad(){
this.ndSvContent.on(cc.Node.EventType.TOUCH_START, (event) => {
this.udpatePosSt(event);
}, this);
}
udpatePosSt(event) {
let pos = this.getCellPosByEvent(event);
if (pos[0] < 0 || pos[0] >= this.blockInfoList.length ||
pos[1] < 0 || pos[1] >= this.blockInfoList[0].length) {
return;
}
switch(this.mouseOp) {
case 0:
break;
case 1:
this.blockInfoList[pos[0]][pos[1]] = 1;
break;
case 2:
this.blockInfoList[pos[0]][pos[1]] = 2;
break;
case 3:
this.blockInfoList[pos[0]][pos[1]] = 0;
break;
default:
break;
}
},
drawBlockMask() {
for (let x = 0; x < this.blockInfoList.length; x++) {
let xList = this.blockInfoList[x];
for (let y = 0; y < xList.length; y++) {
let st = xList[y];
if (st) {
this.gphPath.rect(x * this.cellW, y * this.cellH, this.cellW, this.cellH);
this.gphPath.fillColor = st == 1 ? this.colorBlock : this.colorMask;
this.gphPath.fill();
}
}
}
},
运行结果:
这样编辑器基本上就可以使用了,下一节基于当前编辑的信息,实现一个A星寻路算法,测试当前的地图阻挡信息。