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

原创 2004年10月31日 19:20:00

飞机类游戏中子弹是必不可少的,他们数量很多且充斥着整个屏幕,这些随机或者有着一定AI的小物体,实现起来不是总那么容易,有时候你不得不考虑很多和效能有关的问题。我们之前定义了GameObject,很大程度上就是为了方便的重用Sprite,因为我们有很多的子弹,不可能没增加一个子弹都是一个Sprite,我需要共享同一个Sprite。我们通过继承GameObject来实现。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

下面分析一下这个子弹类:

它将继承自GameObject

记录子弹的个数;

一个子弹的状态数组,记录各个子弹的类型type,位置x,y,速度vx,vy,是否存活alive等等。

初始化子弹

一个绘制方法,将子弹画到屏幕上。

一个碰撞检测方法。

 

好了先这样吧,以下是我们子弹类的定义,注意这种思想——重用Sprite,这很重要。(这里参考了tony的很多设计)

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

  public void resetDeadBullet(){

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

      if(bullets[i][5]==0){//dead bullet

        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);而处理更是简单了一些——直接结束了游戏。如果不是如此,比如处理后并不是简单的结束游戏,我们就不得不设计的复杂一些。可能就不是将碰撞简单的以飞机为中心了。我们需要设计好游戏事件,设计好碰撞系统。

如果碰撞本身比较复杂,或者子弹数量,种类增加时,我们线性的遍历数组就不能总是对所有的子弹都检测,可能屏幕需要分区,不处于一个区域的单位不检测。

总之当你想想你的1934时,将不在是想象着子弹,飞机什么的,你要思考一个系统。

总结一下子弹类的公共接口:

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小游戏入门之旅(四)加入子弹群,实现碰撞运算

作者:favoyang 文章来源:J2ME开发网飞机类游戏中子弹是必不可少的,他们数量很多且充斥着整个屏幕,这些随机或者有着一定AI的小物体,实现起来不是总那么容易,有时候你不得不考虑很多和效能有关的...
  • mobilechannel
  • mobilechannel
  • 2005年05月24日 14:47
  • 2135

J2ME 2D小游戏入门之加入子弹群

  • zgqtxwd
  • zgqtxwd
  • 2008年05月01日 05:43
  • 133

J2ME 2D小游戏入门之旅

CSDN 首页 → 移动频道首页 → 栏目文章列表http://mobile.csdn.net/List.aspx?Column=edfb0da7-e3b1-495d-b38c-5e362c42a78...
  • liulcsy
  • liulcsy
  • 2005年05月28日 16:52
  • 713

android 游戏 实战打飞机游戏 子弹生成与碰撞 以及爆炸效果(5)

android 子弹的生成 以及爆炸效果
  • liudao7994
  • liudao7994
  • 2016年06月01日 13:51
  • 4869

J2ME 2D小游戏入门之旅(八) 源码

源码:说明一下,请不要将里面的图片用于商业目的,有什么问题的话联系tony(yesming),我的纯粹是学习之用。他的blog:blog.csdn.net/yesming源码请上 www.j2mede...
  • alikeboy
  • alikeboy
  • 2004年10月31日 20:07
  • 1981

J2ME 2D小游戏入门之旅(八)源码

作者:favoyang 文章来源:J2ME开发网八、源码源码:说明一下,请不要将里面的图片用于商业目的,有什么问题的话联系tony(yesming),tony的blog地址为http://blog.c...
  • mobilechannel
  • mobilechannel
  • 2005年05月24日 14:58
  • 3374

使用quick-cocos2dx-lua 实现的小游戏(包含碰撞检测,触屏发子弹)

使用quick-cocos2dx-lua 实现的小游戏(包含碰撞检测,触屏发子弹)
  • In_Zihuatanejo
  • In_Zihuatanejo
  • 2015年10月28日 13:46
  • 1136

【Java_项目篇<1>】--JAVA实现坦克大战游戏--坦克发射子弹(三)

前期相关文章【Java_项目篇】–JAVA实现坦克大战游戏–画出坦克(一) 【Java_项目篇】–JAVA实现坦克大战游戏–坦克移动+添加敌方坦克(二)一、任务需求添加hero坦克子弹并且发射。二、...
  • qq_24653023
  • qq_24653023
  • 2016年08月20日 21:33
  • 10832

JAVA游戏简单碰撞原理

一、游戏效果图:玩家飞机与敌机碰撞 或子弹与敌机碰撞,产生爆炸效果,敌机与子弹在爆炸后消失。 二、实现原理:检测原理的两个对象是否碰撞,JAVA提供了Rectangle这个类,里面的...
  • JackLei__
  • JackLei__
  • 2014年11月21日 21:36
  • 2722

[cocos2d-x] 打飞机子弹敌机碰撞检测

自己做了一个简单的打飞机游戏,比较粗糙,下面把子弹和敌人的产生,移动,碰撞的代码拿出来给大家参考参考...
  • u011784589
  • u011784589
  • 2013年10月17日 10:58
  • 2827
收藏助手
不良信息举报
您举报文章:J2ME 2D小游戏入门之旅(四) 加入子弹群,实现碰撞运算
举报原因:
原因补充:

(最多只允许输入30个字)