实现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) ; }
b实现
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) ; }
使用的时候直接调用keyHold(),keyDown(),keyUp()就可以了
两种实现都不错,但是我更倾向于第一种,从代码清晰度和健壮程度来说,都很好
比如有的手机键盘不支持多键输入,当按下两个键以后,只会响应一个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); }
Begin 和 End 之间也是可以响应的
我的输出 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*****************
Trackback from your site.