3.1 游戏用户界面(Canvas)
Canvas类是低级用户界面的画布,所有的图形图像绘制和用户交互(包括按键、指针和Command)都由 这个类来负责。在此将详细讲述这个类的使用方法。
3.1.1 屏幕属性
Canvas类是实现低级API的Displayable类的子类,它提供了绘制方法以及应用程序所忽略的一 些低级事件的处理方法,由于Canvas类的paint方法被声明为抽象方法,所以Canvas类也是一个抽象类。应用程序如果要使用,则必须扩展 Canvas类。
在创建Canvas类的子类时,要求程序提供paint方法的实现。低级事件处理方法未声明为抽象方法,其默 认实现为空,也就是说可以什么都不做。因而,应用程序无须提供每个事件的处理方法,应用程序只需要重载其感兴趣的事件处理方法即可。
Canvas类的构造函数声明为protected,可以在子类的构造函数中调用super(),在实际应用 中,一般不用调用。所有需要处理低级事件以及需要在显示屏幕上完成图形绘制的类都必须按照下面的形式重写Canvas类:
class myCanvas extends Canvas
{
…
void paint(Graphics g)
{
}
…
}
显示屏幕上能够实际用于绘制的区域因设备的不同而有所差异,因此具有较好移植性的应用程序一般不定好屏幕的尺 寸,而是通过调用getHeight()和getWidth()方法来获得具体尺寸。例如:
int width = getWidth(); //获取屏幕的宽度属性
int height = getHeight(); //获取屏幕的高度属性
Canvas的坐标原点位于左上角,其最下角的 坐标为(即getWidth()和getHeight()返回的数值),屏幕的上部分为设备保留部分,用来向用户指示电量、信号强度、设备状态等,下面部 份用于MIDP实现设置或菜单,既可以是应用程序设置的Command软键,也可以是MIDP实现自动设置的菜单等软键,其位置由系统决定。
如果没有设置为全屏模式,即使没有设置任何软键,画布也无法占用这部分空间,如图3-1所示。
Canvas本身有两种状态,一种是普通默认情况下的状态,一种是全屏状态,可以用 setFullScreenMode()方法来对其设定。
两者之间的区别在于当使用全屏状态时,Title、Ticker以及Command都无法在屏幕上显示,而且 当调用setFullScreenMode()时,不管是什么模式,都会调用sizeChanged()这个方法,并传入屏幕的高度和宽度作为其参数。
可以使用setFullScreenMode(true)方法,然后观察Canvas的绘图区域是否发生改 变。
System.out.println(getHeight()); //输出非全屏高度
setFullScreenMode(true); //将Canvas画布设置为全屏幕属性
System.out.println(getHeight()); //输出全屏高度
编译、运行程序,控制台输出某个模拟器在设置Canvas全屏模式前后的高度分别为177和196。可见调用 setFullScreenMode方法后,屏幕的可绘制区域发生了改变。
调用setFullScreenMode(true)后,将触发sizeChanged事件,此事件从系统接 收两个参数,即为Canvas全屏后的width和height,通过这个事件可以获得新的宽、高。如果Canvas当前不可见,那么 sizeChanged会等到showNotify方法调用之前改变当前屏幕的大小参数。
protected void sizeChanged(int w, int h)
{
width = w ;
height = h ;
}
但要注意,setFullScreenMode和sizeChanged并不是同步的,如果调用了 setFullScreenMode(true)之后,立即使用屏幕宽度和高度,仍然有可能是非全屏模式的值。
此外有的设备调用setFullScreenMode(true)后,不会触发sizeChanged,而是 立即返回,因此通过getWidth和getHeight能够马上获得新的屏幕大小参数。
实际上Command的显示与否依赖于设备,有 的设备虽然使用了全屏模式,但仍然能看到Command,也就是说全屏模式未必有效。但是如果Command软键无法在屏幕上显示,而且已经为 Command设置相应功能,那么,按下对应的软键仍然会有相应的功能菜单,如图3-2所示。如何在Canvas中使用Command将在后面讨论。
3.1.2 屏幕绘制
paint(Graphics g)方法用来绘制屏幕,这个方法是一个抽象方法,应用程序必须实现这个方法才能绘制任何图形,如果没有实现这个方法应用程序将不被编译。paint方法被 传入一个Graphics对象g,g所设置的矩形区域定义了屏幕上可绘制的区域,也就是需要重绘的区域。
应用程序不一定要了解paint调用的底层实现,并在这个假定基础上只绘制画布区域中像素的部分。这样做的原 因在于paint方法的特殊性,它可能会被多个repaint方法调用,其中的一些可能来自程序之外,则应用程序只绘制它认为是必需的地方。
注意 | 在paint方法调用返回后,其中的Graphics对象上的操作是未被定义的,因此应用程序不需 要将这个Graphics对象缓存起来,它只能在这个方法范围之内使用。 |
Graphics对象有如下属性。
n 绘制目标为显示屏幕,如果使用双缓冲,则其绘制目标是屏幕的后台缓冲。
n 剪裁区域应该包括画布上至少一个像素。
n 当前颜色是黑色。
n 当前字体为默认字体,可以通过Font.getDefaultFont()得到。
n 画笔风格为SOLID。
n 坐标系统的原点位于画布的左上角。
n Canvas是可见的,调用isShow()应该返回true。
例如下面的代码使用Graphics对象将Canvas画布用单色进行填充。
public void paint(Graphics g)
{
g.setColor(0xFFFFFF); //将画笔颜色设置为白色
g.fillRect(0,0,width,height); //将屏幕填充为白色
}
3.1.3 绘制基本操作
Graphics类可以提供简单的2D几何绘图功能,它与J2SE中的java.awt.Graphics类 非常相似。Gaphics类提供的唯一一种绘图模式为像素替换,在这种模式下,目标像素将替换为用来绘图的Graphics对象所指定的当前像素值。
1.Graphics对象的获取
取得Graphics对象有两个方法,用paint方法传入参数,还可以用Image类的 getGraphics方法。两者区别在于paint方法得到的Graphics对象可以利用相关方法在屏幕上绘图,而利用getGraphics方法得 到的Graphics对象主要用于绘制后台缓冲。
2.Graphics的具体作用
Graphics类的作用就是在屏幕或者后台缓冲上绘制2D几何图形,这些图形主要包括以下3种。
n 文本:使用当前画笔颜色和设备所能支持的字体绘制指定的字符串或者字符。绘制文本时涉及颜色模型、字体类。
n 图像:可以从图像文件中绘制,也可以从缓存中绘制,图像分成可变图像和不变图像,在绘制过程中涉及到Image类。
n 简单的2D几何图形:这些简单的图形包括直线、矩形、弧、圆角矩形、三角形等。
3.坐标系统
画图时在图形相关方法中使用的坐标不代表像素本身,坐标是像素与像素之间空格所构成的坐标。图形的坐标系统 (也就是原点坐标(0,0))定位到绘图空间的左上角,x轴向右延伸,y轴向下延伸,如图3-3所示。
4.复制区域
在MIDP 2.0中还支持对整块区域的复制,可以调用copyArea方法来复制大块的区域。
public void copyArea(int x_src,int y_src,int width, int height,int x_dest, int y_dest, int anchor);
这个区域是用矩形(x_src, y_src, width, height)来确定的,(x_src, y_src)代表源区域的起始坐标,width和height分别代表区域的宽和高,区域的锚点放置在绘制目标的(x_dest, y_dest)上。
copyArea方法将源区域中的内容原封不动地复制到目标区域上,即使源区域和目标区域有重叠部分,这种复 制性的绘制也会完成。
3.1.4 绘制直线
在Graphics的坐标系统中,直线的表示方法是使用它的两个端点坐标表示L:(x1,y1,x2,y2), 实际上是连接坐标(x1,y1)和(x2,y2) 得到一个坐标的集合,然后连接每个坐标右下角的像素就能够得到这条直线。
例如直线(1,0,5,0)连接坐标(1,0)和(4,0)得到一个坐标集合 (1,0)、(2,0)、(3,0)、(4,0)、(5,0),那么这条直线就是由这4个坐标右下角的像素填充得到。
直线(0,1,0,4)得到坐标集合: (0,1)、(0,2)、(0,3)、(0,4)。这条直线由这4个坐标右下角的4个像素表示。
直线(1,2,2,8)的表示不是特别明显,连接两点得到坐标集合(1,2)、(1,3)、(1,4)和 (2,5)、(2,6)、(2,7)、(2,8),这些像素的选取规则为:连接两个端点得到一条直线,取最靠近这条直线的坐标(坐标只能是整数),并且优 先选取右边、下边的坐标。
直线(6,2,6,2)起点和终点是一个点,则由这个像素本身来表示。这些直线在坐标中的表示如图3-4所 示。
绘制直线可以调用Graphics对象的drawLine方法,该方法有4个参数,分别输入x,y起 点坐标,x、y终点坐标。例如:
g.drawLine(2,2,5,5); //绘制线条
g.drawLine(1,2,2,8); //绘制线条
注意 | 如果直线的绘制超出屏幕,则超出部分的像素将被忽略,因此在使用直线时要考虑屏幕的大小限制。 |
3.1.5 绘制弧形
Graphics对象也可以被用来绘制和填充弧形,例如圆和椭圆。弧形的表示方法为 Arc(x,y,w,h,startAngle,arcAngle),它们都由坐标系上的一个轮廓所限定。绘制方法为:
(1)以坐标(x,y)为起点,沿x轴正方向延伸w个 单位,沿y轴的正方向延伸h个单位,得到一个矩形,此虚拟矩形内切绘制一个椭圆(如果w和h相 等,则为圆)。
(2)以矩形的中心为圆心,以时钟3点的方向为0°,逆时针为正方向,从0°正方向旋转startAngle 度,和椭圆相交得到一条直线和一个交点。
(3)从这条直线开始,正方向旋转arcAngle度,得到另一条直线和交点,这样就得到了一个两交点之间的 圆弧。
(4)这个圆弧和两条直线得到一个封闭的区域, 弧线的绘制和填充就以这个封闭区域为基础。整个绘制过程如图3-5所示。
绘制弧线时,根据弧线得到一个与之最接近的坐标集合,然后填充这些坐标左下角的像素。填充弧时,只对在封闭区 域内的像素进行填充。
对于一个360°的弧线,它会覆盖一个宽为w+1,高为h+1的矩形, 而填充弧则覆盖一个宽为w,高为h的矩形,其中w和h都不为0。
如果w和h为0,则填充弧不会影响任何像素,而只要不全为0,绘制弧则 可能绘制一条直线。Graphics提供了两个方法来分别进行弧形的绘制和填充,例如:
g.setColor(0x000000); //设置画笔颜色为黑色
g.drawArc(5,5,120,60,0,360); //绘制一个弧形
g.setColor(0x00FFFF); //设置画笔颜色为淡蓝色
g.fillArc(10,10,150,70,30,80); //填充一个弧形
3.1.6 绘制圆角矩形
Graphics也支持绘制和填充圆角矩形,圆 角矩形是矩形和弧的组合。圆角弧形的坐标表示方法为:RoundRect(x,y,w,h,arcWidth,arcHeight),它的矩形部分用 Rect(x,y,w,h)表示,弧形部分用 Arc(x,y,2*arcWidth,2*arcHeight,0,360)表示,然后由0°开始从圆心分割为90°的4个部分,分别和矩形4个角相 切,组合成一个圆角矩形。圆角矩形的绘制原理如图3-6所示。
Graphics提供了两个方法,分别来进行圆角矩形的绘制和填充,例如:
g.setColor(0x000000); //设置画笔颜色为黑色
g.drawRoundRect(30,40,120,120,20,10); //绘制一个圆角矩形
g.setColor(0x00FF00); //设置画笔颜色为绿色
g.fillRoundRect(60,70,30,60,30,30); //填充一个圆角矩形
3.1.7 绘制三角形
MIDP 2.0新增了一个方法用来填充一个三角形,该方法原型为:
fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3);
该方法的6个参数分别代表了三角形3个顶点的X、Y轴坐标。例如:
g.setColor(0x000000); //设置画笔颜色为黑色
g.fillTriangle(30, 40, 30, 100, 10, 0); //填充一个三角形
3.1.8 绘制笔触的设置
绘制直线、圆弧、矩形和圆角矩形时可以选择使用SOLID或者DOTTED这两种画笔风格。Graphics 对象提供的画笔风格分为两类。
n SOLID:值为0,表示当前画笔为1个像素宽的实线,填充紧靠指定坐标的右下端像素。
n DOTTED:值为1,表示当前画笔为点线,打点频率和长度由MIDP实现决定,直线和弧线的终点不能保证被绘制,矩形的交点也无法保证被绘制。
setStrokeStyle方法用来设置画笔风格,getStrokeStyle方法用来获取当前的画笔风 格,可以使用Graphics对象在任何地方设置画笔风格,设置后会取代前面的设置,影响后续操作,直到再次改变其设置。例如:
g.setStrokeStyle(Graphics.DOTTED); //将笔触风格设置为点线
g.drawLine(10,20,100,20); //绘制线条
g.drawLine(5,50,5,50); //绘制线条
注意 | 画笔风格不影响填充、文本和图像的绘制操作。 |
3.1.9 双缓冲技术
双缓冲技术是编写J2ME游戏程序的关键技术之一。实际上,双缓冲技术是计算机动画的一项传统技术。造成屏幕 闪烁的主要原因在于,画面在显示的同时程序又在改变它,于是画面闪烁。
解决办法是在内存中开辟一片区域作为后台画面,程序对它更新、修改,完成后再显示它。这样被显示的图像永远是 已经完全画好的图像,程序修改的将不是正在被显示的图像。当然还有其他方法可以解决屏幕闪烁问题,但使用双缓冲技术是一种值得推荐的解决方案。
有些设备本身就支持双缓冲,每次都是先把屏幕重画在缓冲之中,然后再绘制在显示屏幕上,而不是直接绘制在显示 屏幕上。可以使用Canvas类的isDoubleBuffer方法判断设备是否具有双缓冲。
可变图像可以很容易地用作屏幕外缓冲。改写前面绘制不变图像的代码,将所有的绘制都放在可变图像中,然后一次 性地将可变图像绘制到屏幕上去。
package doublebufferdemo;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import java.io.*;
public class ImageCanvas extends Canvas
{
private Image buffer; //可变图像,作为绘制缓冲
private Image image; //不变图像,用来加载图片文件
public ImageCanvas()
{
try
{
image = Image.createImage("/tree.png"); //加载图片文件
}catch(java.io.IOException e)
{
System.out.println(e.getMessage()); //处理I/O异常
}
buffer = Image.createImage(this.getWidth(), this.getHeight());
//用一个可变图像作为绘制缓冲
Graphics bg = buffer.getGraphics(); //获取缓冲的Graphics对象
bg.setColor(0xFFFFFF);
bg.fillRect(0, 0, getWidth(), getHeight()); //填充整个屏幕
bg.drawImage(image,this.getWidth()/2,this.getHeight()/2, Graphics.VCENTER|Graphics.HCENTER);
}
public void paint(Graphics g)
{
g.drawImage(buffer,0,0,g.TOP|g.LEFT); //将缓冲区上的内容绘制到屏幕上
}
}
编译、运行程序,其结果和前面完全相同,但是却采用了双缓冲技术。对于双缓冲的使用,可以总结出以下几点。
n 定义一个Graphics对象bg和一个Image对象buffer,按屏幕大小建立一个缓冲对象赋给buffer,然后取得buffer的 Graphics对象赋给bg。在这里,Graphics对象可以理解为缓冲的屏幕,Image对象则可当成缓冲屏幕上的图片。
n 在bg(缓冲屏幕)上用drawImage()和drawString()等语句画图,相当于在缓冲屏幕上画图。
n 调用repaint()语句,它的功能是告知系统调用paint()来完成真实屏幕的显示。这里需要注意的是,paint()是一个系统调用语句,不能手 工调用,只能通过paint()语句来调用。
n 在paint(Graphics g)函数里,将buffer(缓冲屏幕上的图片)画到真实屏幕上。
以上的步骤虽然看似繁琐,但是效果还是很不错的。如果想在屏幕上显示什么东西,只要画在bg上,然后调用 repaint()将其显示出来就可以了。
继承于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的模拟器中游戏的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://hi.baidu.com/feng131719/blog/item/b431e0b50547207f8ad4b267.html