工具软件   办公软件   操作系统   网络安全   设计在线   程序开发   教程宝典   软件下载   软件论坛
您的位置:软件 > 开发者网络 > 开发工具 > 移动开发 > 正文
J2ME 2D小游戏入门之加入子弹群
[文章信息]
作者:朱晓华
时间:2004-11-06
出处:J2ME开发网
责任编辑:方舟
[文章导读]
飞机类游戏中子弹是必不可少的,他们数量很多且充斥着整个屏幕,这些随机或者有着一定AI的小物体
advertisement
热点推荐
· 真没想到VB也可以这样用之指针技术
· 禁止QQ登录的方法
· 给你的XML文件做个数字签名
· ImageReady制作“焰火”小动画
· Java加密和数字签名编程快速入门
[正文]
  飞机类游戏中子弹是必不可少的,他们数量很多且充斥着整个屏幕,这些随机或者有着一定AI的小物体,实现起来不是总那么容易,有时候你不得不考虑很多和效能有关的问题。我们之前定义了GameObject,很大程度上就是为了方便的重用Sprite,因为我们有很多的子弹,不可能没增加一个子弹都是一个Sprite,我需要共享同一个Sprite。我们通过继承GameObject来实现。

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

  它将继承自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]);

}

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);来更新整个状态数组。

  子弹如何绘制?

  我们首先写了一个绘制单个子弹的方法,然后便利数组调用paint(g,i);来绘制整个状态数组。

  子弹如何碰撞?

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

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

  子弹更新?

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

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

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

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

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

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

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

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

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

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

  到此为止,我们的游戏已经初具规模了,下一步是加入效果类,嘿嘿有点意思了…

天极社区邀请您:写博客日记  上传相片   论坛聊天  订阅电子杂志  推荐网摘   免费图铃工具
笔名:   请您注意:

 遵守国家有关法律、法规,尊重网上道德,承担一切因您的行为而直接或间接引起的法律责任。

 天极网拥有管理笔名和留言的一切权利。
评论:
 
发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
相关内容焦点新闻
  • J2ME 2D小游戏入门之控制飞机移动
  • J2ME 2D小游戏入门之游戏的框架
  • J2ME学习之温故而知新篇
  • MIDP 2.0 Media API为游戏增加音效
  • J2ME网络应用程序性能探讨
  • 民营家电商排队造手机 设备商全面杀入
  • 英特尔澄清杨旭任职传闻 官方没宣布此消息
  • 国资委河北密制联通拆分方案
  • 垃圾邮件害人害企害国 清除垃圾邮件不手软
  • 中兴携手阿尔卡特 全球逐鹿CDMA
  • 用友总裁王文京:誓将ERP变成“大众消费”
  • 香港消费者委员会:数码相机最贵未必最好
  • 外电称中兴正评估西门子手机业务 或能并购
  • Advertisement

    天极无线


    奇妙科幻|美好风光|清风车影|漫画卡通|星座生肖|明星写真|动物世界
    老鼠爱大米
    挥着翅膀的女孩
    女人味
    栀子花开
    白月光
    刚刚好
    江南
    快乐崇拜
    亲爱的你怎么不在我身边
    小薇
    2002年的第一场雪
    有多少爱可以重来
    我的地盘
    七里香
    情人
     
    老鼠爱大米 老板电话
    冲动的惩罚 七里香
    我不是黄蓉 女生撒娇
    盛夏的果实 坚持到底
    孤单北半球 眉飞色舞
    挪威的森林 可爱女人
    最浪漫的事 老板电话

    CSEEK搜索