J2ME飞行射击类游戏一
2012-07-09 20:21
246 查看
实例说明:
1.实例规则
玩家控制一架飞机(该项目用一矩形代替![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif)
);按手机方向键可以控制飞机上下左右移动,但飞机不能出屏幕,按中间键可向前方发射子弹,按新号键,飞机发射炮弹的火力会逐渐增强,当炮弹触屏后会自动消失。
2.实例效果:
该实例在模拟器上的运行效果如下:![](http://my.csdn.net/uploads/201207/09/1341835569_2177.jpg)
飞机的初始火力
![](http://my.csdn.net/uploads/201207/09/1341835608_1851.jpg)
按*号键后的火力
3.类设计:
(1)com.main包下的MainMidet主类和MyCanvas画布类;
①.MainMidlet主类:
package com.main; import javax.microedition.lcdui.Display; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; public class MainMidlet extends MIDlet { public MainMidlet() { //显示游戏画布类 Display.getDisplay(this).setCurrent(new MyCanvas()); } public void exit() { try { destroyApp(true); } catch (MIDletStateChangeException e) { e.printStackTrace(); } this.notifyDestroyed();// 通知结束应用程序 } protected void destroyApp(boolean arg0) throws MIDletStateChangeException { } protected void pauseApp() { // 由被呼叫或其他原因使程序暂停 } protected void startApp() throws MIDletStateChangeException { } }
②.MyCanvas游戏画布类
package com.main; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import com.data.FontLib; import com.data.ScreenData; import com.stage.GameStage; import com.stage.SuperStage; public class MyCanvas extends Canvas { private Image backscreen;//后台屏幕 private Graphics backgraphics;//后台画笔 public static final int FPS = 20;//游戏每秒刷新率 private SuperStage stage;//当前舞台对象的引用 private int key;//用户按键的键值 private int frame; private long frametimestar = 0; private int totalframe = 20; public MyCanvas() { this.setFullScreenMode(true); key = -100; backscreen = Image.createImage(ScreenData.SCREENWIDTH,ScreenData.SCREENHEIGHT); backgraphics = backscreen.getGraphics(); stage = new GameStage(this);//默认为GameStage //启动游戏线程 new GameThread().start(); } protected void paint(Graphics g) { g.drawImage(backscreen, 0, 0, 20);//将后台屏幕渲染到前台设备 } //将游戏元素绘制在后台屏幕上 public void render(){ frame++; backgraphics.setColor(-1);//设置颜色为白色 backgraphics.fillRect(0, 0, ScreenData.SCREENWIDTH, ScreenData.SCREENHEIGHT); stage.draw(backgraphics);//渲染舞台 if(frametimestar == 0){ frametimestar = System.currentTimeMillis(); } if(System.currentTimeMillis() - frametimestar >= 1000){ totalframe = frame; frame = 0; frametimestar = 0; } drawFPS(); } private void drawFPS(){//将每秒刷新的频率(每秒刷新的帧数)绘到屏幕上以便观察和衡量游戏的刷新速度; backgraphics.setColor(0xffff0000);//设置画笔的颜色 Font defaultfont = backgraphics.getFont();//得到设画笔的字体 backgraphics.setFont(FontLib.MEDIUM);//设置画笔字体 backgraphics.drawString("FPS:"+totalframe, 0, 0, 20); backgraphics.setFont(defaultfont); } public void input(){//接收用户输入 stage.input(key);//调用游戏舞台接收用户输入的input方法 } public void releaseKey(){ key = -100;//在做单键按下时,用户释放按键,键值无条件归为-100; } public void logic(){//处理游戏逻辑 stage.logic();//调用游戏舞台的逻辑 } protected void keyPressed(int keyCode) {//用户的单键按下事件 key = keyCode; } protected void keyReleased(int keyCode) {//用户单键释放事件 key = -100; } private class GameThread extends Thread{//游戏线程 public void run(){ while(true){ long start = System.currentTimeMillis(); input();//用户输入 logic();//游戏逻辑 render();//渲染 repaint();//请求重绘 long end = System.currentTimeMillis(); if(end - start <= 1000/FPS){//每秒刷新的次数 try { Thread.sleep(1000/FPS - (end - start)); } catch (InterruptedException e) { e.printStackTrace(); } }else{ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
(2)com.data包下的字体接口FontLib和屏幕数据接口ScreenData;
①FontLib常用字体接口:(封装了常用字体);
package com.data; import javax.microedition.lcdui.Font; //封装常用字体 public interface FontLib { Font SMALL = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL); Font MEDIUM = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_MEDIUM); Font LARGE = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_LARGE); }
②ScreenData屏幕数据接口(封装了手机屏幕的宽高和键盘的按键对应的值);
package com.data; import javax.microedition.lcdui.Canvas; public interface ScreenData { int SCREENWIDTH = 240;//屏幕宽 int SCREENHEIGHT = 320;//屏幕高 //左右上下及*号键 int LEFT = -3; int RIGHT = -4; int UP = -1; int DOWN = -2; int STAR = Canvas.KEY_STAR; }
(3)com.statge游戏舞台类的设计:
设计思想:每一个游戏都应该有游戏菜单,游戏帮助,游戏设置,游戏大厅界面;每个界面好比是一个舞台,用户在游戏菜单,玩游戏,游戏帮助,游戏设置中的切换,可以看作是舞台之间的相互切换;所有的游戏舞台可以抽象出一个父类(SuperStage);父类中有一个游戏画布Mycanvas类对象的引用,并且包含了以下抽象方法:初始化舞台(init());处理逻辑(logic);处理舞台按键事件(input());绘制舞台(draw());释放舞台资源(gc());
①SuperStage舞台抽象类的设计
package com.stage; import javax.microedition.lcdui.Graphics; import com.main.MyCanvas; public abstract class SuperStage { protected MyCanvas canvas; public SuperStage(MyCanvas canvas) {// 每一个舞台都A this.canvas = canvas; } public abstract void init();// 初始化舞台 public abstract void gc();// 释放舞台资源 public abstract void logic();// 处理逻辑 public abstract void draw(Graphics g);// 绘制舞台 public abstract void input(int key);// 处理舞台按键事件 }
②子类游戏舞台类(GameStage)的设计;
这里只写了GameStage类继承SuperStage;以后可以根据游戏的具体情况设置相应的舞台类;如(菜单舞台(MenuStage),设置舞台(SetStage)),GameStage类的代码具体如下:package com.stage; import javax.microedition.lcdui.Graphics; import com.data.ScreenData; import com.game.Bullet; import com.game.Plane; import com.main.MyCanvas; public class GameStage extends SuperStage { private Plane myplane;//游戏飞机类型的成员变量 public GameStage(MyCanvas canvas) { super(canvas); init(); } public void init() {//初始化游戏飞机的位置 int w = 50; int h = 30; myplane = new Plane((ScreenData.SCREENWIDTH>>1) - (w >> 1), (ScreenData.SCREENHEIGHT-h-10), w, h); } public void gc() {//释放资源 } public void input(int key) {//用户输入并根据相应的情况移动飞机的位置 if(key == ScreenData.LEFT){ myplane.move(-5, 0); if(myplane.rect.x<=0){ myplane.rect.x=0; return; } }else if(key == ScreenData.RIGHT){ myplane.move(5, 0); if(myplane.rect.x>=ScreenData.SCREENWIDTH-myplane.rect.w){ myplane.rect.x=ScreenData.SCREENWIDTH-myplane.rect.w; return; } }else if(key == ScreenData.UP){ myplane.move(0, -5); if(myplane.rect.y<=0){ myplane.rect.y=0; return; } }else if(key == ScreenData.DOWN){ myplane.move(0, 5); if(myplane.rect.y>=ScreenData.SCREENHEIGHT-myplane.rect.h){ myplane.rect.y=ScreenData.SCREENHEIGHT-myplane.rect.h; return; } }else if(key == ScreenData.STAR){//增加火力 myplane.power += 2; canvas.releaseKey(); } } long start = 0; public void logic() {//更新逻辑 if(start == 0){ start = System.currentTimeMillis(); } //更新飞机子弹容器 if(System.currentTimeMillis() - start >= 100){//每隔100毫秒飞机自动开火 myplane.fire(); start = 0; } //更新子弹的逻辑 //从容器中取出子弹并移动 for (int i = 0; i < myplane.bullet_v.size(); i++) { Bullet temp = (Bullet) myplane.bullet_v.elementAt(i); temp.move(0, -6); if(temp.outScreen()){ temp.visible = false; myplane.bullet_v.removeElementAt(i); i--; } } } public void draw(Graphics g) { myplane.draw(g); for (int i = 0; i < myplane.bullet_v.size(); i++) { Bullet temp = (Bullet) myplane.bullet_v.elementAt(i); temp.draw(g); } } }
(4)com.gameitem包下的Ractangle类设计:
为什么要设计这个类呢;我们可以这样想,子弹和飞机都有自己的x,y坐标和宽高属性,我们可以将他们的x,y坐标和宽高属性封装成一个矩形;生成一个子弹对象货飞机对象的时候都生成一个矩形对象 存储对应子弹或者飞机的坐标和宽高属性。Rectangle类的代码如下
package com.gameitem; import com.data.ScreenData; public class Rectangle { public int x,y; public int w,h; public Rectangle(int x,int y,int w,int h) { this.x = x; this.y = y; this.w = w; this.h = h; } public void move(int dx,int dy){ this.x += dx; this.y += dy; } public boolean outScreen(){//判断是否出屏 if(this.x + this.w <= 0 || this.x >= ScreenData.SCREENWIDTH || this.y + this.h <= 0 || this.y >= ScreenData.SCREENHEIGHT) return true; return false; } }
(5)com.game包下的飞机类(Plane)和子弹类(bullet)的设计;
①Plane类的设计:
Plane除了有包含自身坐标和宽高属性的矩形类成员变量外,还应该有存储子弹的容器类Vector对象;用于存储子弹,同时飞机应该有开火(fire()),移动(move())和绘图(draw())方法;Plane类的代码具体如下:
package com.game; import java.util.Vector; import javax.microedition.lcdui.Graphics; import com.gameitem.Rectangle; public class Plane { public Rectangle rect; public int power ; public Vector bullet_v; public Plane(int x,int y,int w,int h) { this.rect = new Rectangle(x, y, w, h); this.power = 1; bullet_v = new Vector(); } public void move(int dx,int dy){ this.rect.move(dx, dy); } public void draw(Graphics g){ g.setColor(0xff0000ff); g.fillRect(this.rect.x, this.rect.y, this.rect.w, this.rect.h); } public void fire() {//飞机开火 int w = 6; int h = 12; //开火的时候向飞机的子弹容器中添加子弹 for(int i = -power/2; i <= power/2 ; i++){ Bullet temp = new Bullet(this.rect.x+this.rect.w/2 - w/2 + i*10, this.rect.y-h+6, w, h); this.bullet_v.addElement(temp); } } }
②子弹类(Bullet)的设计
Bullet除了有包含自身坐标和宽高属性的矩形类成员变量外,同时应该有移动(move())和绘图(draw())方法;Bullet类的代码具体如下:
package com.game; import javax.microedition.lcdui.Graphics; import com.gameitem.Rectangle; public class Bullet { public Rectangle rect; public boolean visible; public Bullet(int x,int y,int w,int h) { rect = new Rectangle(x, y, w, h); this.visible = true; } public void move(int dx,int dy){ this.rect.move(dx, dy); } public boolean outScreen(){ return this.rect.outScreen(); } public void draw(Graphics g){ if(!visible) return; g.setColor(0xffff0000); g.fillRect(this.rect.x, this.rect.y, this.rect.w, this.rect.h); } }
注意:如果子弹出屏幕后,还对其进行重绘,也不从游戏飞机的子弹容器中移除;随着飞机的开火(fire())功能被调用,容器中的子弹越来越多,屏幕上要绘制的子弹对象越来越多,这样对内存的消耗逐渐变大,最终耗尽内存,如果上面的程序不进行出屏检测和在出片后移除子弹,FPS会逐渐减小,整个游戏的绘图将会出现问题;让我们取出出屏检测和移除子弹,随着游戏的运行,将会出现如下图情况:
![](http://my.csdn.net/uploads/201207/09/1341848340_7386.png)
其次,我们也可以在飞机类和子弹类中加入input ();logic();gc()等方法,减少gamestage中这些方法的代码量。
相关文章推荐
- 自己早期做的一个基于j2me的飞行射击类游戏
- 飞行射击类游戏,Helloworldgame
- 飞行射击类游戏开发实战(系列)-窗口建立
- Unity3d触摸屏控制2D飞行射击类游戏角色
- (转)Android游戏开发之飞行射击类游戏原理实现(二十)
- 非常经典的飞行射击类游戏飞离神庙源码
- j2me打包,FPS射击类游戏的实现
- Android游戏开发之飞行射击类游戏原理实现(二十)
- 一个最最简单的飞行射击游戏(J2ME)的大体框架介绍
- Android游戏开发之飞行射击类游戏原理实现(二十)
- 飞行射击类游戏原理实现
- Android游戏开发之飞行射击类游戏原理实现(十)
- j2me打包,FPS射击类游戏的实现-3G手机开发公开课-东方尚智,3g数字内容学院
- 非常经典的飞行射击类游戏飞离神庙源码
- 飞行游戏程序设计要点【做J2ME游戏时候的一些心得】
- 非常经典的飞行射击类游戏飞离神庙源码
- J2ME网络编程以及网络游戏的实现
- 如何把J2ME游戏移植到Android平台
- J2ME平台A-RPG游戏地图数据处理
- J2ME手机游戏开发--背景绘制