GameCanvas是Canvas的子类
本例程将用到Display,Sprite,GameCanvas,Runnable等
Sprite:精灵类,可以把Sprite看作游戏中的某角色(如主角),Sprite可实现角色便移动,便改变自身形象
1.于 com.sk.model 建立UFOCanvas 类,继承GameCanvas,实现Runnable接口
package com.sk.model;
import java.io.IOException;
import java.util.Random;
import java.util.Vector;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.control.ToneControl;
public class UFOCanvas extends GameCanvas implements Runnable{
private Display display;
private Sprite ufoSprite;
private boolean sleeping;
private int ufoXSpeed,ufoYSpeed;
private Random rand;
//帧率:一幅幅图片连续快速移动从而形成动画,1s内切换的图片数30帧,线程休眠33毫秒,25帧,休眠40毫秒
private int frameRate=33;
private boolean isCenter;
//小行星集合
private Vector roidSprite;
private Image roidImage;
//坚持的时间
private long startTime;
private long endTime;
private boolean gameOver;
//音频部分
private Player tonePlayer;
//输入延迟
private int inputDelay;
public UFOCanvas(Display display){
super(true);
this.display=display;
this.initTune();
}
//音频初始
private void initTune(){
byte tempo=30;
byte d4=16;
byte d2=32;
byte C4=ToneControl.C4;
byte A6=(byte)(C4+21);
byte B6=(byte)(C4+23);
byte G5=(byte)(C4+19);
byte G4=(byte)(C4+7);
byte D5=(byte)(C4+14);
byte rest=ToneControl.SILENCE;
byte[] encounterSeq={
ToneControl.VERSION,1,
ToneControl.TEMPO,tempo,
ToneControl.BLOCK_START,0,
A6,d4,B6,d4,G5,d4,G4,d4,D5,d2,rest,d2,
ToneControl.BLOCK_END,0,
ToneControl.PLAY_BLOCK,0,
ToneControl.PLAY_BLOCK,0
};
try {
tonePlayer = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
tonePlayer.realize();
ToneControl tc=(ToneControl) tonePlayer.getControl("ToneControl");
tc.setSequence(encounterSeq);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MediaException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void playTune(){
try {
tonePlayer.start();
} catch (MediaException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void closeTune(){
tonePlayer.close();
}
private void stopTune(){
try {
tonePlayer.stop();
} catch (MediaException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void start(){
display.setCurrent(this);
ufoXSpeed=ufoYSpeed=3;
startTime=System.currentTimeMillis();
rand=new Random();
try {
ufoSprite=new Sprite(Image.createImage("/com/sk/imgs/ufo.png"));
ufoSprite.setPosition((this.getWidth()-ufoSprite.getWidth())/2, (this.getHeight()-ufoSprite.getHeight())/2);
ufoSprite.defineCollisionRectangle(2, 2, ufoSprite.getWidth()-1, ufoSprite.getHeight()-1);
//行星群
roidSprite=new Vector();
//行星图
roidImage=Image.createImage("/com/sk/imgs/roid.png");
//初始1个行星
Sprite roid=new Sprite(roidImage,roidImage.getWidth(),roidImage.getHeight());
roid.defineCollisionRectangle(2, 2, 12, 12);
roidSprite.addElement(roid);
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("loading image error");
e.printStackTrace();
}
sleeping=false;
new Thread(this).start();
}
public void stop(){
this.sleeping=true;
}
private void update(){
if(gameOver){
int keyState=this.getKeyStates();
if((keyState & this.FIRE_PRESSED)!=0){
ufoSprite.setPosition((this.getWidth()-ufoSprite.getWidth())/2, (this.getHeight()-ufoSprite.getHeight())/2);
//清空行星
roidSprite.removeAllElements();
//重置 1颗行星
Sprite roid=new Sprite(roidImage,roidImage.getWidth(),roidImage.getHeight());
roid.defineCollisionRectangle(2, 2, 12, 12);
roidSprite.addElement(roid);
gameOver=false;
//重新计时
startTime=System.currentTimeMillis();
//音频
this.stopTune();
}
return;
}
//音频(遭遇)
if(rand.nextInt() % 500 ==0){
playTune();
}
if(++inputDelay>1){
ufoXSpeed=ufoYSpeed=0;
//按键
int keyState=this.getKeyStates();
if((keyState & this.LEFT_PRESSED)!=0){
ufoXSpeed-=2;
}else if((keyState & this.RIGHT_PRESSED)!=0){
ufoXSpeed+=2;
}
if((keyState & this.UP_PRESSED)!=0){
ufoYSpeed-=2;
}else if((keyState & this.DOWN_PRESSED)!=0){
ufoYSpeed+=2;
}
//开始 移动
if(rand.nextInt()%2==0){
ufoXSpeed=Math.min(Math.max(ufoXSpeed, -6), 6);
ufoYSpeed=Math.min(Math.max(ufoYSpeed, -6), 6);
}
}
//ufo
ufoSprite.move(ufoXSpeed, ufoYSpeed);
checkBounds(ufoSprite);
//roid
for(int i=0;i<roidSprite.size();i++){
Sprite roid=(Sprite)roidSprite.elementAt(i);
roid.move(1+i, 1-i);
checkBounds(roid);
//碰撞
if(ufoSprite.collidesWith(roid, true)){
//音频(冲突)
try {
Manager.playTone((byte)(ToneControl.C4-12), 500, 100);
} catch (MediaException e) {
// TODO Auto-generated catch block
System.out.println("冲突处");
}
//位置
ufoSprite.setPosition((this.getWidth()-ufoSprite.getWidth())/2, (this.getHeight()-ufoSprite.getHeight())/2);
roid.setPosition(0, 0);
gameOver=true;
//碰撞时间
endTime=System.currentTimeMillis();
return;
}
}
//增加难度,6秒增加一颗roid
if((System.currentTimeMillis()-startTime)/1000>6*roidSprite.size()){
Sprite roid=new Sprite(roidImage,roidImage.getWidth(),roidImage.getHeight());
roid.defineCollisionRectangle(2,2,12,12);
roidSprite.addElement(roid);
}
}
private void draw(Graphics g){
g.setColor(0xFFFFFF);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
if(isCenter){
g.drawString("Fire", (this.getWidth()-ufoSprite.getWidth())/2, (this.getHeight()-ufoSprite.getHeight())/2, Graphics.HCENTER|Graphics.TOP);
isCenter=false;
}
//统计信息
g.setColor(0xFF0000);
if(!gameOver){
g.drawString("时间:"+(System.currentTimeMillis()-startTime)+"毫秒", 0, 0, Graphics.LEFT|Graphics.TOP);
}else{
g.setFont(Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_MEDIUM));
g.drawString("GAME OVER", (this.getWidth()-ufoSprite.getWidth())/2, (this.getHeight()+ufoSprite.getHeight())/2, Graphics.HCENTER|Graphics.TOP);
g.drawString("坚持了:"+(endTime-startTime)/1000+"秒", (this.getWidth()-ufoSprite.getWidth())/2,(this.getHeight()+ufoSprite.getHeight())/2+g.getFont().getHeight(), Graphics.LEFT|Graphics.TOP);
g.drawString("确认键...继续", (this.getWidth()-ufoSprite.getWidth())/2,(this.getHeight()+ufoSprite.getHeight())/2+g.getFont().getHeight()*2, Graphics.LEFT|Graphics.TOP);
}
g.setFont(Font.getDefaultFont());
//ufo
ufoSprite.paint(g);
//roid
for(int i=0;i<roidSprite.size();i++){
Sprite roid=(Sprite)roidSprite.elementAt(i);
roid.paint(g);
}
this.flushGraphics();
}
//出界
private void checkBounds(Sprite sprite){
if(sprite.getX()<-sprite.getWidth()){
sprite.setPosition(this.getWidth(), sprite.getY());
}else if(sprite.getX()>this.getWidth()){
sprite.setPosition(-sprite.getWidth(), sprite.getY());
}
if(sprite.getY()<-sprite.getHeight()){
sprite.setPosition(sprite.getX(),this.getHeight());
}else if(sprite.getY()>this.getHeight()){
sprite.setPosition(sprite.getX(),-sprite.getHeight());
}
}
public void run() {
// TODO Auto-generated method stub
Graphics g=this.getGraphics();
while(!sleeping){
this.update();
this.draw(g);
try {
Thread.sleep(frameRate);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//com.sk.model包UFOCanvas的思路:多线程进行update(),draw(),start()控制此GameCanvas开始工作,stop()停止GameCanvas,CheckBounds()进行边界检测,start()开始工作后,开启新线程不断进行update(),draw(),从而效果便是游戏的连续运动了
2.Midlet调用 UFOCanvas
package com.sk.view;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import com.sk.model.UFOCanvas;
public class UFOForm extends MIDlet implements CommandListener{
private UFOCanvas canvas;
private static Command CMD_EXIT=new Command("退出",Command.EXIT,1);
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
// TODO Auto-generated method stub
}
protected void pauseApp() {
// TODO Auto-generated method stub
}
protected void startApp() throws MIDletStateChangeException {
// TODO Auto-generated method stub
canvas=new UFOCanvas(Display.getDisplay(this));
canvas.addCommand(CMD_EXIT);
canvas.setCommandListener(this);
canvas.start();
}
public void commandAction(Command c, Displayable d) {
// TODO Auto-generated method stub
if(c.equals(CMD_EXIT)){
try {
destroyApp(true);
notifyDestroyed();
} catch (MIDletStateChangeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//本代码可编译后,运行,体验过段时间后,再理解,效果会比较好