在MIDP2.0中,把sprite封装成为了一个类,在这个sprite类里面系统自动实现精灵的碰撞:
public final boolean collidesWith(TiledLayer t, boolean pixelLevel)
public final boolean collidesWith(Image image, int x, int y, boolean pixelLevel)
boolean型的变量pixelLevel的作用是用来指定是像素级碰撞检测还是矩阵级的,一般来说,可以通过规定矩阵交叉的值来决定碰撞的精确性,通常进行碰撞检测的矩阵的大小都比实际的图片的大小要小一些。
运动着的精灵与静止的事物的碰撞:(这里的精灵主要指的是主角等比较大的物体)
在碰撞的时候应该将精灵运动的步长考虑进去,否则就可能出现精灵插到了物体里面去的情况。
初步构思:
在碰撞检测函数里面增加一个判断,如果当精灵与静止物体的距离(产生碰撞的两点之间的距离)小于运动步长dx时就把当然精灵的坐标直接改变为到与物体碰撞时的状态。具体代码:
public boolean bCollidesWith(int X,int Y,byte[] tempRange){//只是简单的测试水平方向的碰撞
if(Math.abs(X-postionX)-range[0]/2-tempRange[0]/2<dx){
if(direction==1){
postionX+=Math.abs(X-postionX)-range[0]/2-tempRange[0]/2;//right
}
else if(direction==0){
postionX-=Math.abs(X-postionX)-range[0]/2-tempRange[0]/2;//left
}
}
return postionX+range[0]/2<=X&&postionX+range[0]/2+tempRange[0]/2>=X
|| postionX<=X+tempRange[0]/2+range[0]/2&&postionX>X+range[0]/2;
}
其实这样的碰撞检测函数是有缺陷的,在一些情况下面会出现精灵穿过障碍物的情况,因为这个函数的设计在考虑的时候只考虑到了一维的情况,在处于同一条直线上面进行碰撞,这样的检测函数已经够了,甚至可以说判断碰撞检测的范围选的有些大了,但是如果放在了二维下面这样是不对的,即使加上了Y坐标的判断,也会出现漏洞。
即使这样:
return postionX+range[0]/2<=X&&postionX+range[0]/2+tempRange[0]/2>=X&&
postionY <= Y &&postionY >= Y - tempRange[1]
||
postionX<=X+tempRange[0]/2+range[0]/2&&postionX>X+range[0]/2&&
postionY <= Y &&postionY >= Y - tempRange[1]
||
postionX+range[0]/2<=X&&postionX+range[0]/2+tempRange[0]/2>=X&&
postionY >= Y &&postionY <= Y + this.range[1]
||
postionX<=X+tempRange[0]/2+range[0]/2&&postionX>X+range[0]/2&&
postionY >= Y &&postionY <= Y + this.range[1]
这个碰撞检测函数是对矩形区域的四个顶点进行判断,这里就只看左下角的点。但X坐标在范围 postionX+range[0]/2<=X&&postionX+range[0]/2+tempRange[0]/2>=X就在x坐标上面符合碰撞的要求,但是应该指出的是这个范围在二维下面小了一点。假如从障碍物的上方,且两个物体的中心处在一条直线上面的时候,就出了问题了。假如PostionX=200,X=200,range[0]=6,tempRange[0]=56,那么这是PostionX+range[0]/2>X,PostionX+range[0]/2<X-tempRange[0]/2的,按照这个检测函数,精灵将无法碰撞到障碍物的.表现出来就是直接穿过了障碍物了.
所以将检测的范围扩大,改写检测函数 :(注,所有的检测函数中的坐标点:PostionX,PostionY,X,Y都是在精灵的下,中位置)
return postionX >= X &&
postionX <= X + tempRange[0] / 2 + this.range[0] / 2 &&
postionY >= Y &&
postionY <= Y + this.range[1]
||
postionX <= X && postionX + this.range[0] / 2 + tempRange[0] / 2 >= X &&
postionY >= Y &&
postionY <= Y + this.range[1]
||
postionX >= X && postionX <= X + tempRange[0] / 2 + this.range[0] / 2 &&
postionY <= Y &&
postionY >= Y - tempRange[1]
||
postionX <= X && postionX + this.range[0] / 2 + tempRange[0] / 2 >= X &&
postionY <= Y &&
postionY >= Y - tempRange[1]
这个函数在原来的基础上范围扩大了range[0]/2,这样就不会出现上面的漏洞了,而且这个函数是考虑到了的所有的情况,只要当前检测点处在障碍物的范围类就会返回TRUE。
下面的问题是,用这个函数进行碰撞检测就已经足够了吗?答案是否定的。
这样的碰撞检测至少还存在两个方面的问题:还是无法处理精灵插到障碍物里面去的情况,特别是在非爆炸类碰撞时这是肯定不行的,比如二维空间里面的一个球去撞一个物体,撞到以后被反弹回来。
另外一个问题就是,有时候物体或者精灵的形状是不规则的,如果只是用矩形检测,可能会太粗略,就可能出现没有碰撞到物体就被判断为碰撞到的情况。
下面一个问题一个问题的解决:
第一个问题:
对于爆炸类的碰撞就无需考虑这个问题了,因为这样的碰撞,在碰撞发生以后精灵的状态就会发生改变,比如子弹击中目标以后会发生爆炸等等。
其实在前面一维的情况的时候就已经考虑过这个问题了,只是那个时候的解决方法不是很好而且也不能用到二维的情况下。对于这样的问题,检测函数不需要进行任何改变,只是在调用检测函数的时候需要作一些变动,已经进行碰撞处理的时候都是判断当前的检测是否出于碰撞检测的范围类,如果不是就让精灵继续往前。其实这样做就间接的造成了精灵插到障碍物里面去的现象。例如当然检测点不在范围类,但是与检测范围边界的距离小于精灵移动的步长,下一个状态的时候精灵的坐标就回移动一个步长的距离,这个时候精灵已经插到了障碍物里面去了,当前状态就是当前paint()函数所画的状态,所以在屏幕上面表现出来的就是精灵插入到了障碍物里面去了。
下面进行改进,进行处理的时候我们是判断精灵的下一个状态是否发生了碰撞,如果没有就继续前进,如果发生了,就再进行一次判断,判断检测点的坐标是否已经处在范围的里面,如果是,就调整精灵的坐标,使它的坐标值在下一个状态的时候处于一个合理的位置,比如前面的碰撞反弹,就可以让检测点处于碰撞范围的边界上面。