j2me的事件响应主要通过keyCode来操作,对于手机上的keyCode有如下2个问题:
手机上的导航键,左右软件的keyCode在不同机器上不同,需要做移植。导航键的上下左右,中间件需要和数字键盘上对应,我们玩手机游戏的时候,这2个操作都行的。
由于这2个问题,我们在判断上下左右以及确定功能的时候,会有移植机型和相同功能映射到不同键位的麻烦。这是蛋疼的问题,因为游戏中上下左右等等操作是非常繁多的。我们就会想,如果有一套虚拟的键值,没有这2个蛋疼的问题就好了。其实是有的,我们先看一下,Canvas系统类为我们定义的按键常量:
public static final int UP = 1; public static final int DOWN = 6; public static final int LEFT = 2; public static final int RIGHT = 5; public static final int FIRE = 8; public static final int GAME_A = 9; public static final int GAME_B = 10; public static final int GAME_C = 11; public static final int GAME_D = 12; public static final int KEY_NUM0 = 48; public static final int KEY_NUM1 = 49; public static final int KEY_NUM2 = 50; public static final int KEY_NUM3 = 51; public static final int KEY_NUM4 = 52; public static final int KEY_NUM5 = 53; public static final int KEY_NUM6 = 54; public static final int KEY_NUM7 = 55; public static final int KEY_NUM8 = 56; public static final int KEY_NUM9 = 57; public static final int KEY_STAR = 42; public static final int KEY_POUND = 35;
我来解释一下,0-9就是Num0-Num9,上下左右导航键就是up,down,left,righ, 导航中间键就是fire,gameABCD对应gameAction的转化值(这个后面说),star是#,poun是*号。
我们可以直接用Canvas的常量来匹配KeyCode,但是有2个问题, 1)没有左右软件, 2)NUM4和left都要执行左边的功能等等。
所以,我们接下来看Canvas帮我们实现了一个getGameAction方法,方法是干什么用的呢? 其实就是消除如上2)的问题。
protected void keyReleased(int keyCode) { keyCode = this.getGameAction(keyCode); }
这句话就是系统根据自己的情况,把keyCode映射一个相对的gameAction值。
意义就是经过上面的调用产生如下效果:
原有的keyCode为NUM4 或 导航left都会映射到 Canvas.left
原有的keyCode为NUM6 或 导航lright都会映射到 Canvas.right
NUM7,9,1,3映射到GameABCD
这样一来经过,this.gameAction我们只要判断left,up,down,fire就可以判断导航键和数字键盘的2映射了。
现在,还剩下一个问题,那就是左右软件的问题,Canvas没有为我们搞定这个事情,所以要自己来。我们要在Canvas的基础上封装一套虚拟的键位包括Canvas的键位和左右软件就行了。名字一般叫GameKey,简称GK.
/* * 手机按键的物理值, 不同的机器不同的值, 需要做预编译移植 */ int REAL_SOFT_LEFT = -6; int REAL_SOFT_RIGHT = -7; /* * 游戏逻辑按键 */ int GK_NONE = 0; // 导航上键或NUM8 int GK_UP = 1; // 导航下键或NMU2 int GK_DOWN = 2; // 导航左键或NUM4 int GK_LEFT = 3; // 导航右键或NUM6 int GK_RIGHT = 4; int GK_STAR = 5; int GK_POUND = 6; int GK_SOFT_LEFT = 7; int GK_SOFT_RIGHT = 8; // 导航中键或NUM5 int GK_OK = 9;
左右软件根据手机的真实值做需处理,GK开头的是虚拟按键会被映射到Canvas下面的定义。
/** * 将系统按键值转换为游戏虚拟键值 * * @param keyCode 系统按键值 * @param gameAction 系统游戏按键值 * @return 游戏虚拟按键值 */ public static int getGKCode(int keyCode, int gameAction) { switch(keyCode) { // 左软件 case REAL_SOFT_LEFT: return GK_SOFT_LEFT; // 右软件 case REAL_SOFT_RIGHT: return GK_SOFT_RIGHT; } switch(gameAction) { case Canvas.DOWN: return GK_DOWN; case Canvas.UP: return GK_UP; case Canvas.LEFT: return GK_LEFT; case Canvas.RIGHT: return GK_RIGHT; case Canvas.FIRE: return GK_OK; // 按键"*" case Canvas.KEY_STAR: return GK_STAR; // 按键"#" case Canvas.KEY_POUND: return GK_POUND; } return 0; }
这个方法,只要传入事件触发中的keyCode,和系统调用getGameAction(keyCode)的gameAction值,就可以得到我们自己定义的虚拟键值了。
核心思想是,我们定义了自己的一套GK值无所谓不重复就可以,因为我们要唯一性判定。接下来,我们利用上述方法在事件发生时候,把各种键位值映射到GK上的值。这样一来,我们仅仅在代码判断中GK的键位就确定系统按了什么键位了。至此文中开始的2个问题都解决了。
补充:
有些系统包括我公司的系统是这么定义GK的:
//基本键 public static final int GK_UP = 1 << 0; public static final int GK_DOWN = 1 << 1; public static final int GK_LEFT = 1 << 2; public static final int GK_RIGHT = 1 << 3; public static final int GK_NUM0 = 1 << 4; public static final int GK_NUM1 = 1 << 5; public static final int GK_NUM2 = 1 << 6; public static final int GK_NUM3 = 1 << 7; public static final int GK_NUM4 = 1 << 8; public static final int GK_NUM5 = 1 << 9; public static final int GK_NUM6 = 1 << 10; public static final int GK_NUM7 = 1 << 11; public static final int GK_NUM8 = 1 << 12; public static final int GK_NUM9 = 1 << 13; public static final int GK_STAR = 1 << 14; public static final int GK_POUND = 1 << 15; public static final int GK_SOFT_LEFT = 1 << 16; public static final int GK_SOFT_RIGHT = 1 << 17; public static final int GK_MIDDLE = 1 << 18; public static final int GK_RETURN = 1 << 19; //组合键 public static final int GK_OK = GK_MIDDLE | GK_SOFT_LEFT; public static final int GK_CANCEL = GK_SOFT_RIGHT; public static final int KEY_LEFT = Key.GK_LEFT | Key.GK_NUM4; public static final int KEY_RIGHT = Key.GK_RIGHT | Key.GK_NUM6; public static final int KEY_UP = Key.GK_UP | Key.GK_NUM2; public static final int KEY_DOWN = Key.GK_DOWN | Key.GK_NUM8; public static final int KEY_FRIE = Key.GK_MIDDLE | Key.GK_NUM5;
这里贴了一部分,不方面都贴出来。我解释一下,这样GK的代表的每一个键值,都是被位移到int类型32个bit位上了。
int在java中4个字节,一共32位。
GK_UP = 1 << 0; 就表示32位中第一位是1,其它都是0,
GK_DOWN = 1 << 1; 就表示32位中的第二位是1,其它都是0。
这么做是为了判断按键下按的,用了一个循环队列机制,我不是这么做的,所以我也没这个设置。
大概的意思是:
GK_UP 存储形式 0000 0000 0000 0000 0000 0000 0000 0001
GK_DOWN 存储形式 0000 0000 0000 0000 0000 0000 0000 0010
这个2个键位进行&, |等等位运算就可知道相应的键值了。