摘要

在寻路算法中我们一般使用网格来进行搜索判断,在没接触时自己也好奇怎么生成地图下的网格,我相信也有很多朋友存在好奇,这里简单分享下个人的解决方案,有错误还希望大佬们多多指导。DOME地址

版本说明

使用 CocosCreator 的 2.4.3 版本。

开始

效果演示:

红色代表一个正方形的中心点

蓝色表示该正方形区域为障碍物

img_name

逻辑梳理:

  1. 设置地图节点大小,设置锚点位于左下角(0,0)位置
  2. 获取单个正方形的边长大小
  3. 获取节点下的障碍物并得到具体的行数、列数方便生成布局时标记为改点为障碍物
  4. 生成布局

一、设置地图等:

1.我们在Canvas下新建一个map节点,需要给map节点设置对应的宽度高度,该节点的大小就代表地图的大小,这里我使用的是960 640的画布。

2.并且需要把map节点的Anchor锚点设置到左下角(0,0),使map节点位于第一象限中,这样做的原因是方便计算正方形的大小、位置。

img_name

3.正方形预制体节点

img_name

二、获取正方形的边长大小:

1.获取当前地图map节点的大小,计算需要生成正方形的大小、需要生成多少。

计算逻辑为,初始设定一个正方形的大小,循环通过高度 宽度 / 正方形大小 得到一个可以被整除的最终正方形大小。

列:画布宽度为 960 高度为 640 初始定义正方形大小为 30

  1. 960 / 30 = 32 640 / 30 = 21.33333333333333 不满足整除条件 使默认正方形大小 +1

  2. 960 / 31 = 30.96774193548387 640 / 31 = 20.64516129032258 不满足整除条件 使默认正方形大小 +1

  3. 960 / 32 = 30 640 / 32 = 20 条件满足故正方形大小为 32

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* 计算正方形高度,当前this.node表示map节点
*/
calculateSquareHeight (){
// 地图的高度
let _mapHeight = this.node.height;
// 地图的宽度
let _mapWidth = this.node.width;
// 高度 这里我们定义一个初始的大小,通过程序去计算得到合适的正方形大小
let _alt = 30;
// 是否满足条件
let _isEnd = true;
// 得到指定的正方形的高度,以及需要的数量
while (_isEnd) {
// 行数
let _longNum = _mapHeight / _alt;
// 列数
let _widthNum = _mapWidth / _alt;
if(_longNum % 1 === 0 && _widthNum % 1 ===0){
_isEnd = false;
// 得到每个格子大小
this.altSize = _alt;
// 得到需要多少列
this.longNum = _longNum;
// 得到需要多少行
this.widthNum = _widthNum;
// 计算障碍物所在位置
this.mapForObstacle();
} else {
_alt++;
}
}
}

三、获取节点下的障碍物:

1.如果地图中存在障碍物,我们需要通过设置group把障碍物的分组设置为’MAP_OBSTACLE’,然后进行循环获取每个节点计算当前节点所在的行数、列数并存入Map方便生成布局时判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* 拿到指定节点下的障碍物位置、大小
* this.altSize 表示第二步时获取到的正方形大小
*/
mapForObstacle (){
// 在map节点下新建了level节点并在level节点下放入了障碍物节点
let a = 'Canvas/map/level'
let mapNode = cc.find(a);
// 循环
mapNode.children.forEach((r)=>{
// 判断当前是否为障碍物节点
if(r.group === 'MAP_OBSTACLE'){
// 障碍物宽度的半径
let _widthRadius = r.width - r.width / 2;
// 障碍物高度的半径
let _heightRadius = r.height - r.height / 2;
// 得到障碍物左下角x y位置,方便计算具体位置
let _xRange = r.x - _widthRadius;
let _yRange = r.y - _heightRadius;
// 计算从障碍物左边开始到右边的具体列数
let _columnLeft = Math.ceil(_xRange / this.altSize);
let _columnRight = Math.ceil((r.x + _widthRadius) / this.altSize);
let _a = [];
for(let i = 0,len = _columnRight -_columnLeft;i<=len;i++){
_a[i] = _columnLeft + i;
};
// 得到从下到上的行数
let _lineDow = Math.ceil(_yRange / this.altSize);
let _lineUp = Math.ceil((r.y + _heightRadius) / this.altSize);
let _b = [];
for(let i = 0,len = _lineUp -_lineDow;i<=len;i++){
_b[i] = _lineDow + i;
};
// 进行 行数存储
_b.forEach((r)=>{
let _obsGet = this.obstacleMap.get(r);
if(_obsGet){
let _arr1 = [..._a,..._obsGet];
let _arr = Array.from(new Set(_arr1));
this.obstacleMap.set(r,_arr);

} else {
this.obstacleMap.set(r,_a);
}
});

}
})
// 开始布局
this.generateLayout(this.altSize,this.longNum,this.widthNum);
}

四、生成布局:

1.根据已经得到的数据进行网格的生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* 生成布局
* @param _initSquareHeight 正方形瓦块高度
* @param _initLineNum 初始行数 需要用到的行数
* @param _initColumnNum 初始列数 需要用到的列数
*/
generateLayout (_initSquareHeight:number,_initLineNum:number,_initColumnNum:number){
// 初始行数
let _lineNum = 1;
// 初始列数
let _columnNum = 1;
// 因为坐标位于中间 0.5 0.5 所以需要根据高度除以 2 得到半径 即位置
let _radii = _initSquareHeight / 2;
let _isEnd = true;
let _arr = [];
while (_isEnd) {
// 计算位置
let _x = _columnNum === 1 ? _columnNum *_radii : (_columnNum-1) * _initSquareHeight + _radii;
let _y = _lineNum === 1 ? _lineNum *_radii : (_lineNum-1) * _initSquareHeight + _radii;
// 判断是否在障碍区域r
let _isObsLine = this.obstacleMap.get(_lineNum);
let _color = new cc.Color(255,0,0);
let _type = 0;
if(_isObsLine && _isObsLine.indexOf(_columnNum) >= 0){
_color = new cc.Color(71,53,234);
_type = 1;
}
// 生成节点this.ItemPrefab表示挂载的预制体
let _node = cc.instantiate(this.ItemPrefab);
_node.width = _initSquareHeight;
_node.height = _initSquareHeight;
_node.children[0].color = _color;
_node.setPosition(cc.v2(_x,_y));
// 设置父节点 this.ItemNode表示要生成几点的父节点
_node.parent = this.ItemNode;
_arr.push({type:_type,node:_node});
// 判断是否到达列数
if(_lineNum === _initLineNum && _columnNum === _initColumnNum){
// 表示结束
_isEnd = false;
_arr = [];
} else if(_columnNum === _initColumnNum){
// 初始从1开始
_columnNum = 1;
// 行数增加
_lineNum++;
_arr = [];
} else {
_columnNum++;
}
}

}

结尾:

暂时行更新,写这写这写不下去了…