这个例子适用于场景比较小的,太大的场景这个方法不好
首先获取场景中会和角色发送碰撞的物体
colliderList = []; // 存储所有可碰撞的物体的坐标和宽高
// 草和石头
let box = cc.find("Canvas/GamePanel/obs");
if(box)
{
let list = box.getComponentsInChildren(cc.BoxCollider); // 获取到子节点可用的碰撞器列表
if(list)
{
for(let i in list)
{
if(list[i].enabled)
{// 碰撞器可用
// 这里吧物体坐标和碰撞器的偏移加起来,作为坐标,因为我们计算的实际是碰撞器之间的相对位置
// 我这里玩家和场景中的物体的父节点obs在同一个节点下,obs的坐标是0,0,所以不需要加上父节点的偏移
this.colliderList.push({pos:cc.v2(list[i].offset.x+list[i].node.position.x,list[i].offset.y+list[i].node.position.y),
width:list[i].size.width,height:list[i].size.height});
}
}
}
}
// 走路的时候实时获取到与碰撞物的距离
// moveDir 移动方向 上下左右4个方向
// player 当前计算的玩家node
getColliderDis(moveDir,player)
{
// 根据方向从所有可碰撞的里面找到,距离最近的
let min = -100;// 设置一个开始值
let myCollider = player.getComponent(cc.CircleCollider); // 角色是圆形碰撞器
let my = {pos:cc.v2(player.position.x+myCollider.offset.x,player.position.y+myCollider.offset.y),radius:myCollider.radius}// 角色碰撞器的位置和碰撞器半径
!!!因为我这角色和场景的所有碰撞物体在同一个node下,所以可以直接计算相对位置,如果不是在同一个层级下,需要计算偏移位置后再判断相对位置,或者都转成世界坐标来判断相对位置是否接近碰撞
for(let i=0;i<this.colliderList.length;i++)
{
let num = 0
if(moveDir===GameConfig.RoleDirection.right)
{// 距离碰撞物右侧的,向右移动
// 上下肯定交叉
if(Math.abs(this.colliderList[i].pos.y-my.pos.y)-(my.radius+this.colliderList[i].height/2)<=0)
{// y方向上和玩家的距离减去他们高度一半<0,说明y方向有交叉,往右走会有碰撞
num = this.colliderList[i].pos.x-my.pos.x-(my.radius+this.colliderList[i].width/2); // 得到玩家和右侧碰撞物的空隙距离
}
}
else if(moveDir===GameConfig.RoleDirection.left)
{// 距离碰撞物左侧的,向左移动
if(Math.abs(this.colliderList[i].pos.y-my.pos.y)-(my.radius+this.colliderList[i].height/2)<=0)
{ // y方向上和玩家的距离减去他们高度一半<0,说明y方向有交叉,往左走会有碰撞
num = my.pos.x-this.colliderList[i].pos.x-(my.radius+this.colliderList[i].width/2); // 得到玩家和左侧碰撞物的空隙距离
}
}
else if(moveDir===GameConfig.RoleDirection.up)
{// 距离碰撞物上侧的,向上移动
// 左右肯定交叉
if(Math.abs(this.colliderList[i].pos.x-my.pos.x) -(my.radius+this.colliderList[i].width/2)<=0)
{// x方向上和玩家的距离减去他们宽度一半<0,说明x方向有交叉,往上次走会有碰撞
num = this.colliderList[i].pos.y-my.pos.y-(my.radius+this.colliderList[i].height/2); // 得到玩家和上侧碰撞物的空隙距离
}
}
else if(moveDir===GameConfig.RoleDirection.down)
{// 距离碰撞物下侧的,向下走
// 左右肯定交叉
if(Math.abs(this.colliderList[i].pos.x-my.pos.x) -(my.radius+this.colliderList[i].width/2)<=0)
{// x方向上和玩家的距离减去他们宽度一半<0,说明x方向有交叉,往下走会有碰撞
num = my.pos.y-this.colliderList[i].pos.y-(my.radius+this.colliderList[i].height/2); // 得到玩家和下侧碰撞物的空隙距离
}
}
if(num>0)
{// 间隙距离大于0的
if(min===-100)
{
min = num // 初始赋值
}
if(num<min)
{// 取最小的那个,就是当期最可能撞到的
min = num;
}
}
}
return min;
}
当玩家实时移动的时候调用那个方法
let dis = 10;// 默认每次移动10
let tempDis = this.getColliderDis(this.moveDir,this.node);
if(tempDis>=0&&tempDis<20)// 距离碰撞物小于20就计算下次走的时候最多走多少
{
dis = tempDis-5<=0?0:tempDis-5;// 最后留5像素,不能走,dis是0
}
this.node.y += dis;