# J2ME 2D小游戏入门之旅(四) 加入子弹群，实现碰撞运算

public class Bullets extends GameObject {

private int[][] bullets;//子弹状态数组

private int bulletstotal;//数组的length

private Random rnd;//随机数

public static final int BULLET_TYPE_LEFT=0;//子弹初始化的位置类型

public static final int BULLET_TYPE_RIGHT=1;//分为上下左右四种

public static final int BULLET_TYPE_TOP=2;

public static final int BULLET_TYPE_BOTTOM=3;

private int width,height;//屏幕的高和宽，用于随机子弹位置

public Bullets(Image img,int picwidth,int picheight,int bulletstotal,int width,int height) {

super(img,picwidth,picheight);

this.bulletstotal=bulletstotal;

bullets=new int[bulletstotal][6];

rnd=new Random();

this.width=width;

this.height=height;

}

public void initBullets(){//初始化子弹状态数组

for (int i = 0; i < bullets.length; i++) {

initBullet(i);

}

}

private void initBullet(int i) {//初始化index号子弹

bullets[i][0] = (rnd.nextInt() & 0x7fffffff) % 4; //type

bullets[i][5] = 1; //alive 1表示存活， 0表示死去

switch (bullets[i][0]) {

case BULLET_TYPE_LEFT:

bullets[i][1] = -5;

bullets[i][2] = (rnd.nextInt() & 0x7fffffff) % height;

bullets[i][3] = (rnd.nextInt() & 0x7fffffff) % 3 + 1; //vx

bullets[i][4] = (rnd.nextInt()) % 3; //vy

break;

case BULLET_TYPE_RIGHT:

bullets[i][1] = width + 5;

bullets[i][2] = (rnd.nextInt() & 0x7fffffff) % height;

bullets[i][3] = ( (rnd.nextInt() & 0x7fffffff) % 3 + 1) * -1; //vx

bullets[i][4] = (rnd.nextInt()) % 3; //vy

break;

case BULLET_TYPE_TOP:

bullets[i][1] = (rnd.nextInt() & 0x7fffffff) % width;

bullets[i][2] = -5;

bullets[i][3] = (rnd.nextInt()) % 3; //vx

bullets[i][4] = (rnd.nextInt() & 0x7fffffff) % 3 + 1; //vy

break;

case BULLET_TYPE_BOTTOM:

bullets[i][1] = (rnd.nextInt() & 0x7fffffff) % width;

bullets[i][2] = height + 5;

bullets[i][3] = (rnd.nextInt()) % 3; //vx

bullets[i][4] = ( (rnd.nextInt() & 0x7fffffff) % 3 + 1) * -1; //vy

break;

}

}

public void updata(int i){//根据速度更新i子弹下一桢的位置，碰壁反弹

bullets[i][1]+=bullets[i][3];

bullets[i][2]+=bullets[i][4];

if(bullets[i][1]<-5 || bullets[i][1]>width+5){

bullets[i][3]*=-1;

}

if(bullets[i][2]<-5 || bullets[i][2]>height+5){

bullets[i][4]*=-1;

}

}

private void paint(Graphics g,int i){//绘画出第i个子弹

updataspritepos(i);//更新位置

sprite.paint(g);//绘画Sprtie

}

public void paint(Graphics g) {//绘画整个子弹组

for (int i = 0; i < bullets.length; i++) {

if(bullets[i][5]==0){//死去的子弹不绘画

continue;

}

sprite.setPosition(bullets[i][1],bullets[i][2]); //更新位置

sprite.paint(g);

}

}

public void refreshBullets(Sprite planesprite, boolean needcollision){//刷新字典数组的状态，并作碰撞处理

for (int i = 0; i < bullets.length; i++) {

if(bullets[i][5]==0){ //死去的子弹不更新

continue;

}

if(needcollision){//如果需要碰撞检测

if (isCollision(planesprite, i, 10)) {//如果碰撞，进行处理

//System.out.println("collision ");

Navigate.mc.gameover = true;

Navigate.mc.explosion.sprite.setPosition(bullets[i][1] - 16,

bullets[i][2] - 16);

bullets[i][5] = 0;//杀死碰撞的子弹

continue;

}

}

updata(i);//更新状态

}

}

private boolean isCollision(Sprite sprite,int i,int range){

//判断是否碰撞

//updataspritepos(i);

//return sprite.collidesWith(this.sprite,true);

boolean result=false;

int planeXCenter=sprite.getX()+12;

int planeYCenter=sprite.getY()+12;

int bulletXCenter=bullets[i][1]+3;

int bulletYCenter=bullets[i][2]+3;

if(Math.abs(planeXCenter-bulletXCenter) < range){

if (Math.abs(planeYCenter - bulletYCenter )< range) {

result = true;

}

}

return result;

}

private void updataspritepos(int i){//sprite更新到i字弹的位置

sprite.setPosition(bullets[i][1],bullets[i][2]);

}

/* no use now

for (int i = 0; i < bullets.length; i++) {

initBullet(i);

}

}

}

*/

public void killbullets(Sprite planesprite,int range){杀死一定区域内的子弹

for (int i = 0; i < bullets.length; i++) {

if(bullets[i][5]!=0){//alive bullets

if(isCollision(planesprite, i, range)){

bullets[i][5]=0;

initBullet(i);

}

}

}

}

}

bullets[i][0]表示子弹的类型，有上、下、左、右四种，分别表示子弹飞入屏幕前的四种位置；

bullets[i][1]表示子弹的x坐标；

bullets[i][2]表示子弹的y坐标

bullets[i][3]表示子弹的x方向速度；

bullets[i][4]表示子弹的y方向速度；

bullets[i][5]表示子弹的存活状态；

我们首先写了一个初始化单个子弹的方法，然后便利数组调用initBullet (i)；来更新整个状态数组。

我们首先写了一个绘制单个子弹的方法，然后便利数组调用paintg,i）；来绘制整个状态数组。

有很多种方法，其中sprite本身就提供了边框碰撞检测和基于像素的碰撞检测。前者不太适合我们的游戏，我们的飞机是不规则物体，且飞行游戏对碰撞比较敏感；而后者的效率又得不到我们的信赖，所以我们是用一种半径检测，把飞机近似的看成圆，选取恰当的半径，Math.abs(planeXCenter-bulletXCenter) < range则表明碰撞。

碰撞看似简单，其实是很复杂的问题，值得庆幸的是，二维碰撞相比三维碰撞简单得多。一个小技巧是，宁可让膨胀检测半径变小也不要他变得大——漏掉检测，总比误检测要好得多。

我们利用refreshBullets进行更新，这是主要逻辑部分。这个方法负责便利数组检测碰撞，如果碰撞就将处于碰撞位置的子弹杀死，并作相应的处理，这里是结束游戏并爆炸飞机；否则更新子弹的位置。

我们只是线性的遍历整个的数组，进行碰撞检测，之后是更新位置；但是这样做有一个前提，就是碰撞检测简单而且处理部分也很简单：在这个游戏中，碰撞检测只是子弹群和飞机的检测，碰撞检测在游戏结束后就不执行了（通过控制boolean needcollision）；而处理更是简单了一些——直接结束了游戏。如果不是如此，比如处理后并不是简单的结束游戏，我们就不得不设计的复杂一些。可能就不是将碰撞简单的以飞机为中心了。我们需要设计好游戏事件，设计好碰撞系统。

n         Bullets(Image img,int picwidth,int picheight,int bulletstotal,int width,int height)构造函数

n         public void initBullets()初始化子弹数组

n         public void paint(Graphics g) paint子弹数组

n         public void refreshBullets(Sprite planesprite, boolean needcollision)更新子弹数组状态，碰撞检测、处理等逻辑工作的综合

n         public void killbullets(Sprite planesprite,int range)//稍后解释

• 本文已收录于以下专栏：

举报原因： 您举报文章：J2ME 2D小游戏入门之旅(四) 加入子弹群，实现碰撞运算 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)