原文地址: 实现J2ME游戏的按键(键盘)缓冲
1. 什么是键盘缓冲?
J2ME当中键盘响应是用Canvas下的keyPressed()和keyReleased()方法实现的,所以就有可能出现这种情况: 把所有的键盘响应放在keyPressed()中实现
这样出现三种问题:
- 首先就是无法响应持续按键信息,如RPG游戏有的时候需要选择数量,让玩家选择99,莫非让玩家点99次键盘吗?如果使用MIDP2.0,可以使用getKeyStates()函数,但是又出问题了,在选择菜单的时候,菜单会来回蹦,造成选不中所要选择的菜单,必然还要使用keyPressed()方法,况且2.0也有其他的种种问题....
- 所有键盘响应放在keyPressed()中,当逻辑逐渐变大时,函数执行时间必然会变大,当又有一个keyPressed()事件发生时,后果无法预料....(因为模拟器,真机,响应方式都不相同,还存在支持不支持多按键操作的问题,所以我也没测...)
- 这样,必然会造成相关的逻辑分离,从代码的美观和整体的逻辑上都大打折扣,阅读代码必然会造成困难
2. 什么时候发生键盘响应?
我认为,理论上说是即时响应的,在我测试看来,不存在 Thread.sleep(100) 后系统才调用的事情,所以只要有时间片,虚拟机就会自动调用keyPressed方法
所驳文章地址: http://www.j2megame.cn/bbs/viewthread.php?tid=4246&page=1
相关我的回复: http://www.j2megame.cn/bbs/viewthread.php?tid=4246&page=1#pid37075
见最下方
3. 实现方法
今天用了一天的时间研究了键盘缓冲,看起来就区区几行代码,这一天下来,可是收获不少
下面先来看实现,现在发现两种比较好的实现
a实现
代码:
public void keyPressed(int keyCode){
int value = getKeyValue(keyCode) ; //自己定义的转换键值函数
keyPressedBuffer |= value ;
}
public void keyReleased(int keyCode){
int value = getKeyValue(keyCode) ;
keyReleasedBuffer |= value ;
}
private static void acquireKey(){ //主循环中调用
keyPressed = keyPressedBuffer;
keyReleased = keyReleasedBuffer;
keyCurrent |= keyPressed;
keyCurrent &= ~keyReleased;
keyPressedBuffer = 0;
keyReleasedBuffer = 0;
}
public static boolean keyHold(int gameKey){ //按住
return ((keyCurrent & gameKey)!=0) ;
}
public static boolean keyDown(int gameKey){ //按下
return ((keyPressed & gameKey)!=0) ;
}
public static boolean keyUp(int gameKey){ //抬起
return ((keyReleased & gameKey)!=0) ;
}
代码:
public void keyPressed(int keyCode){
int value = getKeyValue(keyCode) ; //自己定义的转换键值函数
key |= value ;
pressedKey |= value ;
}
public void keyReleased(int keyCode){
int value = getKeyValue(keyCode) ;
key ^= value ;
releasedKey |= value ;
}
private static void acquireKey(){ //主循环中调用
frameKey = key ;
framePressedKey = pressedKey ;
frameReleasedKey = releasedKey ;
pressedKey = 0 ;
releasedKey = 0 ;
}
public static boolean keyHold(int gameKey){ //按住
return ((frameKey & gameKey)!=0) ;
}
public static boolean keyDown(int gameKey){ //按下
return ((framePressedKey & gameKey)!=0) ;
}
public static boolean keyUp(int gameKey){ //抬起
return ((frameReleasedKey & gameKey)!=0) ;
}
两种实现都不错,但是我更倾向于第一种,从代码清晰度和健壮程度来说,都很好
比如有的手机键盘不支持多键输入,当按下两个键以后,只会响应一个keyPressed(),但传说有的手机会响应两个keyReleased().......也就是没有按下,直接弹起按键了......这样第二种方法就会出现问题了,就是因为第二种方法使用的时异或操作符
测试:
1000 & ~1000 = 0000 1000 ^ 1000 = 0000 //按下1000,弹起1000
1000 & ~1001 = 0000 1000 ^ 1001 = 0001 出问题...
同时弹起两个按键?..... 呵呵..不管怎么样,可能会出问题
关于getKeyValue(keyCode)说明:
就是一个自己的键值转换的函数,比如定义 YOUR_LEFT = 1; 如果keyCode是左方向键返回 YOUR_LEFT就可以了,也是各种品牌手机真实键值不同惹得祸...
今天研究一天的成果,如果叙述有误,请提出,共同探讨
虽然这个是对J2ME键盘缓冲的研究,但是我感觉在其他平台上的游戏同样存在着类似的问题,思路是一样的
-----------------------
关于《sleep后响应keyPressed()》我的回复
原文: http://www.j2megame.cn/bbs/viewthread.php?tid=4246&page=1#pid37075
在做项目的时候发现,我从来没有sleep过,但是仍然响应keyPressed()的
使用的是nokia的S60模拟器,使用手机顽童模拟器照样响应,使用fullcanvas
作者也说了是使用nokia的~什么问题...?
莫非WTK是这样的吗?
而且如果有sleep的话,也不是在sleep的时候触发的,看代码
代码:
while(true){
System.out.println("\nBegin");
updateGame();
repaint(0, 0, 172, 208);
serviceRepaints(); //调用System.out.println("paint");
System.out.println("End\n");
Thread.sleep(80);
}
我的输出 aaa************ 为 keyPressed() 输出
1. 正常按键
Begin
paint
End
aaa*****************
Begin
paint
End
Begin
paint
End
aaa*****************
Begin
paint
End
2. 快速按键
aaa*****************
Begin
aaa*****************
paint
aaa*****************
End
Begin
aaa*****************
paint
End
aaa*****************