分享
 
 
 

一步一步学习midp2。0游戏编程(二)

王朝other·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

GameCanvas实际上就是屏幕上一个可绘制区域. Javax.microedition.lcdui.game.GameCanvas 类与javax.microedition.lcdui.Canvas 有以下两点不一样: 图像缓冲以及可以查询按键的状态. 这些改进给游戏开发者更多的便利.

图像缓冲实现了所有的图形对象在后台创建,等他们全部预备好了,再一起绘制到屏幕上去.这使得动画更加流畅.在代码里我已经说明了怎么调用 advance() 方法. ( advance()在 GameThread 对象的主循环中调用.) 你所要做的就是调用paint(getGraphics()) 然后调用 flushGraphics(). 为了让你的代码更加高效,并且你知道屏幕上哪些部分需要重新绘制,你可以调用 flushGraphics()方法.作为实验,把 paint(getGraphics()) 和 flushGraphics() 的调用换成 repaint()以及 serviceRepaints()(假如你的类是继续自Canvas而不是GameCanvas的话).在我的代码中中,他们没有什么明显的区别,但是假如你的程序包含了很多复杂的图形的话,GameCanvas 无疑是一个明智的选择.

当你学习下面的代码的时候,你会发现当我刷新了屏幕以后 (在advance()方法中),我让线程停止了1毫秒. 这除了是为了让新绘制的图像稍稍停留一会, 更重的是它保证了按键查询的正确工作. 我前面已经提到, GameCanvas 和Canvas的按键状态的响应是不一样的. 在 Canvas时代, 假如你想知道按键状态,你必须实现keyPressed(int keyCode),每当有键被按下时,这个方法就被调用. 而 GameCanvas时代, 当你想知道某个键是否被调用的时候,直接调用 getKeyStates()方法就成了. 当然getKeyStates()的返回值会在另外一个线程中被更新,所以在你的游戏主循环中我们最好稍微登上一会,以保证这个值被更新,磨刀不误砍柴功嘛。

GameCanvas的两个方面的优越性是怎么提高绘制性能以及按键响应这个问题现在已经显而易见了。 让我们再回到 GameThread 类, 游戏的主循环首先向 GameCanvas 的子类 (叫做JumpCanvas) 查询按键状态 (参见 JumpCanvas.checkKeys() 方法). 按键事件处理好了以后, GameThread 的主循环调用JumpCanvas.advance() 来让 LayerManager 对图像做适当的更新 (下一节中将会具体介绍) 然后将它们绘制到屏幕上,最后等上一小会。

下面是 JumpCanvas.java的代码:

package net.frog_parrot.jump;

import javax.microedition.lcdui.*;

import javax.microedition.lcdui.game.*;

/**

* This class is the display of the game.

*

* @author Carol Hamer

*/

public class JumpCanvas extends javax.microedition.lcdui.game.GameCanvas {

//---------------------------------------------------------

// dimension fields

// (constant after initialization)

/**

* the height of the green region below the ground.

*/

static int GROUND_HEIGHT = 32;

/**

* a screen dimension.

*/

static int CORNER_X;

/**

* a screen dimension.

*/

static int CORNER_Y;

/**

* a screen dimension.

*/

static int DISP_WIDTH;

/**

* a screen dimension.

*/

static int DISP_HEIGHT;

/**

* a font dimension.

*/

static int FONT_HEIGHT;

/**

* the default font.

*/

static Font FONT;

/**

* a font dimension.

*/

static int SCORE_WIDTH;

/**

* The width of the string that displays the time,

* saved for placement of time display.

*/

static int TIME_WIDTH;

//---------------------------------------------------------

// game object fields

/**

* a handle to the display.

*/

Display myDisplay;

/**

* a handle to the MIDlet object (to keep track of buttons).

*/

Jump myJump;

/**

* the LayerManager that handles the game graphics.

*/

JumpManager myManager;

/**

* whether or not the game has ended.

*/

static boolean myGameOver;

/**

* the player's score.

*/

int myScore = 0;

/**

* How many ticks we start with.

*/

int myInitialGameTicks = 950;

/**

* this is saved to determine if the time string needs

* to be recomputed.

*/

int myOldGameTicks = myInitialGameTicks;

/**

* the number of game ticks that have passed.

*/

int myGameTicks = myOldGameTicks;

/**

* whether or not this has been painted once.

*/

boolean myInitialized;

/**

* The initial time string.

*/

static String myInitialString = "1:00";

/**

* we save the time string to avoid recreating it

* unnecessarily.

*/

String myTimeString = myInitialString;

//-----------------------------------------------------

// gets/sets

/**

* This is called when the game ends.

*/

static void setGameOver() {

myGameOver = true;

GameThread.requestStop();

}

/**

* Find out if the game has ended.

*/

static boolean getGameOver() {

return(myGameOver);

}

//-----------------------------------------------------

// initialization and game state changes

/**

* ConstrUCtor sets the data.

*/

public JumpCanvas(Jump midlet) {

super(false);

myDisplay = Display.getDisplay(midlet);

myJump = midlet;

}

/**

* This is called as soon as the application begins.

*/

void start() {

myGameOver = false;

myDisplay.setCurrent(this);

repaint();

}

/**

* sets all variables back to their initial positions.

*/

void reset() {

myManager.reset();

myScore = 0;

myGameOver = false;

myGameTicks = myInitialGameTicks;

myOldGameTicks = myInitialGameTicks;

repaint();

}

/**

* clears the key states.

*/

void flushKeys() {

getKeyStates();

}

//-------------------------------------------------------

// graphics methods

/**

* paint the game graphics on the screen.

*/

public void paint(Graphics g) {

// perform the calculations if necessary:

if(!myInitialized) {

CORNER_X = g.getClipX();

CORNER_Y = g.getClipY();

DISP_WIDTH = g.getClipWidth();

DISP_HEIGHT = g.getClipHeight();

FONT = g.getFont();

FONT_HEIGHT = FONT.getHeight();

SCORE_WIDTH = FONT.stringWidth("Score: 000");

TIME_WIDTH = FONT.stringWidth("Time: " + myInitialString);

myInitialized = true;

}

// clear the screen:

g.setColor(0xffffff);

g.fillRect(CORNER_X, CORNER_Y, DISP_WIDTH, DISP_HEIGHT);

g.setColor(0x0000ff00);

g.fillRect(CORNER_X, CORNER_Y + DISP_HEIGHT - GROUND_HEIGHT,

DISP_WIDTH, DISP_HEIGHT);

// create (if necessary) then paint the layer manager:

try {

if(myManager == null) {

myManager = new JumpManager(CORNER_X, CORNER_Y + FONT_HEIGHT*2,

DISP_WIDTH, DISP_HEIGHT - FONT_HEIGHT*2 - GROUND_HEIGHT);

}

myManager.paint(g);

} catch(Exception e) {

errorMsg(g, e);

}

// draw the time and score

g.setColor(0);

g.setFont(FONT);

g.drawString("Score: " + myScore,

(DISP_WIDTH - SCORE_WIDTH)/2,

DISP_HEIGHT + 5 - GROUND_HEIGHT, g.TOPg.LEFT);

g.drawString("Time: " + formatTime(),

(DISP_WIDTH - TIME_WIDTH)/2,

CORNER_Y + FONT_HEIGHT, g.TOPg.LEFT);

// write game over if the game is over

if(myGameOver) {

myJump.setNewCommand();

// clear the top region:

g.setColor(0xffffff);

g.fillRect(CORNER_X, CORNER_Y, DISP_WIDTH, FONT_HEIGHT*2 + 1);

int goWidth = FONT.stringWidth("Game Over");

g.setColor(0);

g.setFont(FONT);

g.drawString("Game Over", (DISP_WIDTH - goWidth)/2,

CORNER_Y + FONT_HEIGHT, g.TOPg.LEFT);

}

}

/**

* a simple utility to make the number of ticks look like a time...

*/

public String formatTime() {

if((myGameTicks / 16) + 1 != myOldGameTicks) {

myTimeString = "";

myOldGameTicks = (myGameTicks / 16) + 1;

int smallPart = myOldGameTicks % 60;

int bigPart = myOldGameTicks / 60;

myTimeString += bigPart + ":";

if(smallPart / 10 < 1) {

myTimeString += "0";

}

myTimeString += smallPart;

}

return(myTimeString);

}

//-------------------------------------------------------

// game movements

/**

* Tell the layer manager to advance the layers and then

* update the display.

*/

void advance() {

myGameTicks--;

myScore += myManager.advance(myGameTicks);

if(myGameTicks == 0) {

setGameOver();

}

// paint the display

try {

paint(getGraphics());

flushGraphics();

} catch(Exception e) {

errorMsg(e);

}

// we do a very short pause to allow the other thread

// to update the information about which keys are pressed:

synchronized(this) {

try {

wait(1);

} catch(Exception e) {}

}

}

/**

* Respond to keystrokes.

*/

public void checkKeys() {

if(! myGameOver) {

int keyState = getKeyStates();

if((keyState & LEFT_PRESSED) != 0) {

myManager.setLeft(true);

}

if((keyState & RIGHT_PRESSED) != 0) {

myManager.setLeft(false);

}

if((keyState & UP_PRESSED) != 0) {

myManager.jump();

}

}

}

//-------------------------------------------------------

// error methods

/**

* Converts an exception to a message and displays

* the message..

*/

void errorMsg(Exception e) {

errorMsg(getGraphics(), e);

flushGraphics();

}

/**

* Converts an exception to a message and displays

* the message..

*/

void errorMsg(Graphics g, Exception e) {

if(e.getMessage() == null) {

errorMsg(g, e.getClass().getName());

} else {

errorMsg(g, e.getClass().getName() + ":" + e.getMessage());

}

}

/**

* Displays an error message if something goes wrong.

*/

void errorMsg(Graphics g, String msg) {

// clear the screen

g.setColor(0xffffff);

g.fillRect(CORNER_X, CORNER_Y, DISP_WIDTH, DISP_HEIGHT);

int msgWidth = FONT.stringWidth(msg);

// write the message in red

g.setColor(0x00ff0000);

g.setFont(FONT);

g.drawString(msg, (DISP_WIDTH - msgWidth)/2,

(DISP_HEIGHT - FONT_HEIGHT)/2, g.TOPg.LEFT);

myGameOver = true;

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有