**问题描述:**在项目开发中,使用到了刚体, 在搭建地图过程中,发现两个相邻的砖块,即使贴合的再紧密,但星星人在上面走动的时候还是会有很大概率发生卡顿(被两个刚体的边界处卡住)。为了解决这个问题,我们小组对砖块进行了分类处理。
**处理过程如下:**将所有左上角的砖块(左边和上边都不是砖块的砖块)当做特殊砖块(specialBlock),其余的砖块是普通砖块(normalBlock),对特殊砖块进行特殊操作,使其的碰撞框范围覆盖所有的相邻砖块,特殊砖块的定义如下:
被圈起来的砖块就属于特殊砖块,参与碰撞范围的绘制,其他的砖块则只是普通精灵,没有刚体组件(RigidBody)和碰撞体组件(collider)
实现代码如下:
## 正确绘制特殊砖块的碰撞范围,并将points所需要的点存入到this.blockColliderItemArr 中,以备使用
```
/**
* 正确绘制特殊砖块的碰撞范围,并将points所需要的点存入到this.blockColliderItemArr 中,以备使用
* @param element 特殊砖块本体
* @param i 特殊砖块的横坐标
* @param j 特殊砖块的纵坐标
* @param type 是朝哪个方向遍历 1 下 2 右 3 上 4左
* this.blockArr = []; // 这个数组用来放置被绘制过的砖块
* this.blockColliderItemArr = []; // 一个完整的碰撞盒的坐标点
*/
setColliderRange: function (element, i, j, type) {
var temp = [i, j];
if (type !== 1 && type !== 2 && this.nowBlock[0] === i && this.nowBlock[1] === j) {
// 又回到了起点,那么就结束
// console.log("回到结束点了");
if (type === 3 && j + 1 !== constants.mapEditProperties.column && (this.mapData[i][j + 1].type === constants.elementValue.BLOCK ||
this.mapData[i][j + 1].type === constants.elementValue.BUTTONM)) {
// console.log("经过起始点去了右边");
this.calculateColliderPoints(i, j, 3);
this.setColliderRange(element, i, j + 1, 2);
}
if (type === 3) {
this.blockColliderItemArr.push(cc.p(constants.itemSize.blockColliderSize.x / 2, constants.itemSize.blockColliderSize.y / 2));
}
return;
}
switch (type) {
case 1:
// 下
if (j !== 0 && (this.mapData[i][j - 1].type === constants.elementValue.BLOCK || this.mapData[i][j - 1].type === constants.elementValue.BUTTONM)) {
// 计算要存储的点坐标
this.calculateColliderPoints(i, j, 1);
// 左
this.setColliderRange(element, i, j - 1, 4);
} else if (i + 1 !== constants.mapEditProperties.row && (this.mapData[i + 1][j].type === constants.elementValue.BLOCK ||
this.mapData[i + 1][j].type === constants.elementValue.BUTTONM)) {
// 下
this.setColliderRange(element, i + 1, j, 1);
} else if (j + 1 !== constants.mapEditProperties.column && (this.mapData[i][j + 1].type === constants.elementValue.BLOCK ||
this.mapData[i][j + 1].type === constants.elementValue.BUTTONM)) {
// 右
this.calculateColliderPoints(i, j, 2);
this.setColliderRange(element, i, j + 1, 2);
} else {
// 返回 上
this.calculateColliderPoints(i, j, 2);
this.calculateColliderPoints(i, j, 3);
this.setColliderRange(element, i - 1, j, 3);
}
break;
case 2:
// 右
if (i + 1 !== constants.mapEditProperties.row && (this.mapData[i + 1][j].type === constants.elementValue.BLOCK ||
this.mapData[i + 1][j].type === constants.elementValue.BUTTONM)) {
// 下
this.calculateColliderPoints(i, j, 2);
this.setColliderRange(element, i + 1, j, 1);
} else if (j + 1 !== constants.mapEditProperties.column && (this.mapData[i][j + 1].type === constants.elementValue.BLOCK ||
this.mapData[i][j + 1].type === constants.elementValue.BUTTONM)) {
// 右
this.setColliderRange(element, i, j + 1, 2);
} else if (i !== 0 && (this.mapData[i - 1][j].type === constants.elementValue.BLOCK || this.mapData[i - 1][j].type === constants.elementValue.BUTTONM)) {
// 上
this.calculateColliderPoints(i, j, 3);
this.setColliderRange(element, i - 1, j, 3);
} else {
// 返回 左
this.calculateColliderPoints(i, j, 3);
this.calculateColliderPoints(i, j, 4);
this.setColliderRange(element, i, j - 1, 4);
}
break;
case 3:
// 上
if (j + 1 !== constants.mapEditProperties.column && (this.mapData[i][j + 1].type === constants.elementValue.BLOCK || this.mapData[i][j + 1].type === constants.elementValue.BUTTONM)) {
this.calculateColliderPoints(i, j, 3);
// 右
this.setColliderRange(element, i, j + 1, 2);
} else if (i !== 0 && (this.mapData[i - 1][j].type === constants.elementValue.BLOCK || this.mapData[i - 1][j].type === constants.elementValue.BUTTONM)) {
// 上
this.setColliderRange(element, i - 1, j, 3);
} else if (j !== 0 && (this.mapData[i][j - 1].type === constants.elementValue.BLOCK || this.mapData[i][j - 1].type === constants.elementValue.BUTTONM)) {
// 左
this.calculateColliderPoints(i, j, 4);
this.setColliderRange(element, i, j - 1, 4);
} else {
// 返回 下
this.calculateColliderPoints(i, j, 4);
this.calculateColliderPoints(i, j, 1);
this.setColliderRange(element, i + 1, j, 1);
}
break;
case 4:
// 左
if (i !== 0 && (this.mapData[i - 1][j].type === constants.elementValue.BLOCK || this.mapData[i - 1][j].type === constants.elementValue.BUTTONM)) {
this.calculateColliderPoints(i, j, 4);
// 上
this.setColliderRange(element, i - 1, j, 3);
} else if (j !== 0 && (this.mapData[i][j - 1].type === constants.elementValue.BLOCK || this.mapData[i][j - 1].type === constants.elementValue.BUTTONM)) {
// 左
this.setColliderRange(element, i, j - 1, 4);
} else if (i + 1 !== constants.mapEditProperties.row && (this.mapData[i + 1][j].type === constants.elementValue.BLOCK || this.mapData[i + 1][j].type === constants.elementValue.BUTTONM)) {
// 下
this.calculateColliderPoints(i, j, 1);
// 特殊处理,如果是做下的话,把这个点放入到blockArr中
if (!this.blockArr.includes(temp)) {
this.blockArr.push(temp);
}
this.setColliderRange(element, i + 1, j, 1);
} else {
// 返回 右
// 特殊处理,如果是做下的话,把这个点放入到blockArr中
if (!this.blockArr.includes(temp)) {
this.blockArr.push(temp);
}
this.calculateColliderPoints(i, j, 1);
this.calculateColliderPoints(i, j, 2);
this.setColliderRange(element, i, j + 1, 2);
}
break;
default:
break;
}
},
```
###### calculateColliderPoints()方法用来计算单个碰撞体的点坐标,并将得到的点坐标添加到this.blockColliderItemArr数组中
```
/**
* 计算单个碰撞体的点坐标,并将其添加到this.blockColliderItemArr中
* @param i 当前点的横坐标
* @param j 当前坐标的纵坐标
* @param type 要取的点的类型 1:左上 2:左下 3:右下 4:右上
* this.nowblock 存储的特殊砖块的相对坐标
*/
calculateColliderPoints: function (x, y, type) {
var temp = cc.p();
switch (type) {
case 1:
if (y >= this.nowBlock[1]) {
temp.x = (Math.abs(y - this.nowBlock[1]) - (1 / 2)) * constants.itemSize.blockColliderSize.x;
} else {
temp.x = (-Math.abs(y - this.nowBlock[1]) - (1 / 2)) * constants.itemSize.blockColliderSize.x;
}
if (x > this.nowBlock[0]) {
temp.y = (-Math.abs(this.nowBlock[0] - x) + (1 / 2)) * constants.itemSize.blockColliderSize.y;
} else {
temp.y = (Math.abs(this.nowBlock[0] - x) + (1 / 2)) * constants.itemSize.blockColliderSize.y;
}
break;
case 2:
if (y >= this.nowBlock[1]) {
temp.x = (Math.abs(y - this.nowBlock[1]) - (1 / 2)) * constants.itemSize.blockColliderSize.x;
} else {
temp.x = (-Math.abs(y - this.nowBlock[1]) - (1 / 2)) * constants.itemSize.blockColliderSize.x;
}
if (x > this.nowBlock[0]) {
temp.y = (-Math.abs(this.nowBlock[0] - x) - (1 / 2)) * constants.itemSize.blockColliderSize.y;
} else {
temp.y = (Math.abs(this.nowBlock[0] - x) - (1 / 2)) * constants.itemSize.blockColliderSize.y;
}
break;
case 3:
if (y >= this.nowBlock[1]) {
temp.x = (Math.abs(y - this.nowBlock[1]) + (1 / 2)) * constants.itemSize.blockColliderSize.x;
} else {
temp.x = (-Math.abs(y - this.nowBlock[1]) + (1 / 2)) * constants.itemSize.blockColliderSize.x;
}
if (x > this.nowBlock[0]) {
temp.y = (-Math.abs(this.nowBlock[0] - x) - (1 / 2)) * constants.itemSize.blockColliderSize.y;
} else {
temp.y = (Math.abs(this.nowBlock[0] - x) - (1 / 2)) * constants.itemSize.blockColliderSize.y;
}
break;
case 4:
if (y >= this.nowBlock[1]) {
temp.x = (Math.abs(y - this.nowBlock[1]) + (1 / 2)) * constants.itemSize.blockColliderSize.x;
} else {
temp.x = (-Math.abs(y - this.nowBlock[1]) + (1 / 2)) * constants.itemSize.blockColliderSize.x;
}
if (x > this.nowBlock[0]) {
temp.y = (-Math.abs(this.nowBlock[0] - x) + (1 / 2)) * constants.itemSize.blockColliderSize.y;
} else {
temp.y = (Math.abs(this.nowBlock[0] - x) + (1 / 2)) * constants.itemSize.blockColliderSize.y;
}
break;
default:
break;
}
temp.x = parseFloat(temp.x.toFixed(1));
temp.y = parseFloat(temp.y.toFixed(1));
var i = 0;
for (; i < this.blockColliderItemArr.length; i++) {
if (this.blockColliderItemArr[i].x === temp.x && this.blockColliderItemArr[i].y === temp.y) {
console.log("这个点阵中已经存在这个点了");
return;
}
}
this.blockColliderItemArr.push(temp);
},
```
最后,将计算出来的结果赋值给碰撞框的points属性:
上图中的points数组,这个数组决定了你的碰撞体的碰撞范围,将计算出的顶点数组赋值给这个属性。
代码如下:
##### 带来的收益:
1. 完美解决了星星人在砖块上发生卡顿的问题
2. 大大减少了刚体精灵的绘制数量,对性能有一定的提升