实现J2ME游戏的按键(键盘)缓冲

作者:Wupei  |  发表时间:  |  所属分类:J2ME

1. 什么是键盘缓冲?

J2ME当中键盘响应是用Canvas下的keyPressed()和keyReleased()方法实现的,所以就有可能出现这种情况: 把所有的键盘响应放在keyPressed()中实现

这样出现三种问题:

  1. 首先就是无法响应持续按键信息,如RPG游戏有的时候需要选择数量,让玩家选择99,莫非让玩家点99次键盘吗?如果使用MIDP2.0,可以使用getKeyStates()函数,但是又出问题了,在选择菜单的时候,菜单会来回蹦,造成选不中所要选择的菜单,必然还要使用keyPressed()方法,况且2.0也有其他的种种问题….
  2. 所有键盘响应放在keyPressed()中,当逻辑逐渐变大时,函数执行时间必然会变大,当又有一个keyPressed()事件发生时,后果无法预料….(因为模拟器,真机,响应方式都不相同,还存在支持不支持多按键操作的问题,所以我也没测…)
  3. 这样,必然会造成相关的逻辑分离,从代码的美观和整体的逻辑上都大打折扣,阅读代码必然会造成困难

有这么多问题,当然就要解决,解决办法就是缓冲,就是找个地方把它存起来,用的时候再取


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.

请在这里留言: