GameCanvas类

GameCanvas类

继承于MIDP 1.0的Canvas类的GameCanvas是一个提供了游戏的基本接口的抽象类,除了完全具备原来Canvas类的功能外,还提供了更多开发游戏的便 利,主要为:提供屏幕缓冲绘制机制,并能直接得到设备键盘的物理状态。

3.2.1  GameCanvas概述

GameCanvas(游戏画布)对象能够提供画布的功能,类的定义为:

public abstract class GameCanvas extends Canvas

GameCanvas类是在Canvas类的基础上派生的,并在此之上增加双缓冲和随时查询按键状态的功能。 因为游戏画布类被定义为虚类,所以必须派生新类。GameCanvas类包含的方法如表3-1所示。

表3-1                                                     类GameCanvas方法说明

方 法 名 称

方法原型与作用

GameCanvas

protected GameCanvas(boolean suppressKeyEvents)

构造方法,参数 suppressKeyEvents 表示是否需要处理游戏按键之外的其他按键事件。例如数字键,如果此参数为false,那么按键事件处理方法keyPressed、 keyRepeated、keyReleased在程序运行过程中不会被调用,这样可以提高速度和性能

getGraphics

protected Graphics getGraphics( )

得到画布中脱机屏幕上用于绘制的 Graphics 对象

flushGraphics

public void flushGraphics( )

要求刷新屏幕,这时脱机屏幕上的图像会被绘制到真实屏幕上

flushGraphics

public void flushGraphics(int x, int y, int width, int height)

要求刷新屏幕上指定区域,这时脱机屏幕上指定区域的图像会被绘制到真实屏幕上

getKeyStates

public int getKeyStates()

得到当前按键状态

3.2.2  绘制双缓冲区

要创建一个新的GameCanvas实例,需要通过继承并调用父类的构造函数,如下所示。

protected GameCanvas(boolean suppressKeyEvents);

GameCanvas为这个类的每个实例提供了惟一的图形缓冲区,所有的图形创建和修改都在缓冲区上进行,缓 冲区的大小和GameCanvas全屏幕时的大小一样,但是存在的Ticker或者Command等控件都会影响到GameCanvas的大小。 GameCanvas的当前大小可以通过调用getWidth()和getHeight()方法获得。缓冲区的颜色初始化为白色。

开发者可以调用从GameCanvas实例获得其对应的Graphics对象,而且只有对Graphics对 象操作,才会修改缓冲区的内容,外部资源如其他的MIDlet或者系统级的通知都不会导致缓冲区内容改变。

每一个GameCanvas所拥有的缓冲区都是独立的,考虑到尽量少地使用对象堆栈,最好在游戏中仅仅创建一 个GameCanvas,并且重复利用。

为了将缓冲区中的内容刷新到屏幕上,所需要做的只是先调用getGraphics()方法,获得用来绘制缓冲 区的Graphics对象。刚创建的Graphics对象具有以下默认属性。

n     绘制目标是这个GameCanvas的缓冲区。

n     绘制区域覆盖整个缓冲区。

n     当前颜色是黑色。

n     字体和调用Font.getDefaultFont()返回的相同。

n     绘图模式为SOLID。

n     坐标系统的原点定位在缓冲区的左上角。

返回的Graphics对象将用于绘制属于这个GameCanvas的后备屏幕缓冲区(off-screen buffer),但是绘制后的结果不会立即显示出来,直到调用flushGraphics()方法,将缓冲区中的内容一起绘制到屏幕上去。

注意

每一次调用getGraphics()都会返回一个新的Graphics 对象,对于同一个GameCanvas,返回的Graphics 对象都是针对同一个缓冲区,所以应当在游戏运行前获得并保存Graphics 对象,然后在游戏运行时重复使用。getGraphics()返回一个用以绘制GameCanvas缓冲区的Graphics 对象,对于缓冲区的绘制不会改变屏幕的内容,只有调用flushGraphics()才将缓冲区中的内容绘制到屏幕上去。

flushGraphics()方法将后备屏幕缓冲区的内容输出到显示屏幕上,输出的区域大小和 GameCanvas的大小相同。

绘制实际屏幕的操作不会改变后备屏幕的内容,这个方法会一直等到绘制操作完成后才返回,因此,当这个方法返回 时,应用程序可以立刻对缓冲区进行下一帧后备屏幕的绘制。

如果GameCanvas当前没有显示,或者系统忙而不能执行绘制请求,该方法不进行任何操作就立刻返回。

这种“双缓冲”的机制将使得游戏动画更加流畅自然。此外,如果知道屏幕上哪些部分需要重新绘制,还可以调用 flushGraphics(int x, int y, int width, int height)方法在自定义的区域内进行绘制,而这会使得代码更加高效。

作为试验,笔者把GameCanvas中的对getGraphics()和flushGraphics()方 法的调用换成Canvas中repaint()以及serviceRepaints()方法的调用,两者没有什么明显的区别,但是如果程序包含了很多复杂 的图形,GameCanvas无疑是一个明智的选择。

3.2.3  实现游戏主循环

一个游戏可能提供自己的线程来运行游戏循环:一个典型的循环将检查输入、实现游戏逻辑,然后绘制更新后的用户 界面。

通常,在MIDP 2.0游戏中,GameCanvas充当了游戏“控制器”的功能。GameCanvas除了完成绘制屏幕的功能外,还负责等待并获得用户的输入,进行相应 的处理(改变游戏的状态和移动图层),绘制改变后的游戏界面。下面给出了一个在MIDP 2.0中使用GameCanvas实现游戏循环的代码框架:

//GameCanvas 的实现的游戏线程

Graphics g = getGraphics();                 //获得Graphics对象来绘制后备屏幕缓冲

while (true) {

  int keyState = getKeyStates();            //检查是否有用户输入

  if ((keyState & LEFT_PRESSED) != 0) {      //游戏左键被按下

      sprite.move(-1, 0);                    //进行游戏逻辑操作,这里精灵向左移动

  }

  else if ((keyState & RIGHT_PRESSED) != 0) {   //游戏右键被按下

      sprite.move(1, 0);                     //进行游戏逻辑操作,这里精灵向右移动

  }

  g.setColor(0xFFFFFF);                     //将背景填充为白色

  g.fillRect(0,0,getWidth(), getHeight());

  sprite.paint(g);                          //绘制精灵

  flushGraphics();                          //将缓冲区的内容绘制到真实的设备屏幕上

}

3.2.4  获取键盘状态

前面已经提到,GameCanvas和Canvas的按键状态的响应是不一样的。在Canvas时代,如果想 知道按键状态,必须实现keyPressed()/keyReleased()/keyRepeated(),每当有按键被按下时,这个方法就被调用,而 在GameCanvas时代,如果要检查特定的按键是否被按下,只需要将getKeyStates()返回的值与这些键值进行按位与(&),并根 据计算结果来判断即可。

getKeyStates()返回的bit数据分别代表了不同的按键(例如Up、Down、Fire等)。当 按下某个物理键盘时,其对应的位设置为1,否则将被设置为0,这样做的好处是,无论游戏主循环执行得多慢,键盘事件都不会被忽略。

注意

除非GameCanvas当前可见(通过调用Display.isShown()方法),否则此方 法返回值为0。一旦GameCanvas变为可见,将初始化所有键为未按下状态(0)。

每一次getKeyStates()方法的调用都会清除当前键盘缓冲区,因此理论上说,连续调用两次 getKeyStates(),前一次会清除之前锁定的键盘状态,而后一次会得到反映当前键盘状态的理想值。

当然getKeyStates()的返回值会在另外一个线程中被更新,所以在游戏主循环中最好稍微等一会儿, 以保证这个值被更新。GameCanvas中获得用户输入的代码:

protected void input() {

int keyState = getKeyStates();                    //获得键盘状态

if ((keyState & LEFT_PRESSED) != 0) {             //如果左键被按下

// do something

}

if ((keyState & RIGHT_PRESSED) != 0) {            //如果右键被按下

// do something

}

if ((keyState & FIRE_PRESSED) != 0) {             //如果确定键被按下

// do something

}

}

文本框:图3-7  WTK 2.2中的DefaultColorPhone键盘映射关系

 

 

 

 

 

 

 

 

如图3-7所示,将WTK的模拟器中游戏的A、B、C、D键分别映射到 1、3、7、9这4个键上,而Nokia模拟器将A、B、C、D键映射到7、9、#、*这4个键上。这里并没有使用处理按键事件的方式来得到按键输入,如 果采用这种方法获得按键输入,则一定要调用getGameAction()将按键代码转换为游戏代码。

为了使程序能在不同的设备上运行,就一定要考虑不同设备间键盘布局的特点,在开发程序时不能假设按键的布局方 式。具体的映射关系如表3-2所示。

表3-2                                              getKeyState()方法所返回的键盘值

键    值

相对应的KeyStates值

UP_PRESSED

0x0002 = 2

DOWN_PRESSED

0x0040 = 64

LEFT_PRESSED

0x0004 = 4

RIGHT_PRESSED

0x0020 = 32

FIRE_PRESSED

0x0100 = 256

GAME_A_PRESSED

0x0200 = 512(并非所有设备支持)

GAME_B_PRESSED

0x0400 = 1024(并非所有设备支持)

GAME_C_PRESSED

0x0800 = 2048(并非所有设备支持)

GAME_D_PRESSED

0x1000 = 4096(并非所有设备支持)

注意

不同的设备对于getKeyStates()方法的调用会略有不同,主要体现在:有的设备支持检测 多个键同时按下的情况,而有的设备的不支持getKeyStates()方法,仅仅是通过调用keyPressed()/keyReleased()方法 来代替,因此会产生一定的时延。

由于GameCanvas能够通过getKeyStates()方法主动查询键盘状态,因此也提供了是否抑制 传统键盘事件的选择。

如果希望当游戏运行时,禁止调用KeyPressed()/keyReleased() /KeyRepeated()方法,那么就可以在构造GameCanvas时,在super()中传入true值。如果传入false值,那么一旦按键按 下,就会调用传统的键盘事件处理方法。

注意

键盘抑制只对当前GameCanvas 有效,并且只能抑制Canvas预定义的键盘事件(例如无法抑制手机上的*号键、#号键,以及接听、挂断、Clear等功能键)。


 

 

本文摘自:http://apps.hi.baidu.com/share/detail/31217091

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值