分享
 
 
 

J2ME键盘响应祥解及处理方法

王朝java/jsp·作者佚名  2006-05-17
窄屏简体版  字體: |||超大  

J2ME上的键盘响应估计是继画图后出现Bug最多的地方了,尤其像手机游戏这种键盘操作较多的J2ME程序。在工作的过程中CoCoMo曾不止一次的被问及有关键盘响应的问题,pigham前两天还在为他的游戏在7210上按键不能及时响应而发愁,就在刚才我还在努力的解决着S700上不支持getGameAction()的问题。虽然CoCoMo在这个行业已经工作了一年多了,但是键盘响应的bug仍然时常蹦出来刺激我的神经,所以千万不要小瞧了这个不起眼的keyPressed()

keyPressed()响应的位置:

弄清楚keyPressed()响应的位置对最终解决按键响应不及时很有帮助。理论上keyPressed()是由KVM负责的,当Canvas的子类被Display.setCurrent()之后,只要按下任何按钮就会引发keyPressed()。但这只是某些人一厢情愿的美好愿望,仅限于理论研究的范畴,理论和实际往往相差甚远不是吗。实际上keyPressed()的响应是有位置的,CoCoMo可以用如下程序做一个实验:

while(b_running)

{

updateState();

repaint();

serviceRepaints();

long d = System.currentTimeMillis() - s_curFrameTime;

if (d < 80) Thread.sleep(80 - d);

s_curFrameTime = System.currentTimeMillis();

}

这是一个传统意义上的游戏循环,CoCoMo分别在updateState(),paint()和keyPressed()中加入调试语句如下:

void updateState() {

System.out.println("UpdateState");

}

protected void paint(Graphics g) {

System.out.println("Paint");

}

protected void keyPressed(int keyCode) {

System.out.println("keyPressed");

}

protected void keyReleased(int keyCode) {

System.out.println("keyReleased");

}

然后启动MIDlet,一阵狂按之后,得出如下结果:

UpdateState

Paint

keyReleased

UpdateState

Paint

keyPressed

UpdateState

Paint

keyReleased

keyPressed

你会惊奇的发现keyPressed()和keyReleased()总是在paint()之后,UpdateState()之前。实际上keyPressed()是在线程sleep的时候引发的,也就是说当Canvas这个线程在空闲状态时,KVM才有机会向激活的Display传递消息说有人按了某键,或者KVM总能向Display传递消息,但Display需要在空闲状态时才能调用keyPressed(),至于是哪种方式那是底层实现的事情,我们并不得而知,但有一点是可以肯定的:keyPressed()是在Canvas线程sleep的时候被引发的。这也是按键不响应或延时的根本原因:Canvas线程过于繁忙,没有sleep或很少sleep。解决办法:

一:优化程序,减轻Canvas线程负担,使sleep时间增加。

二:在优化后情况仍然存在,可以在需要按键响应的地方强行使线程sleep(20),从而引发keyPressed()。在我的一个项目中需要频繁创建图片,致使线程过度繁忙,即便在S700这样的机型上也出现了按键响应不及时的问题,我就是这么处理的,对帧速率影响并不大。

J2ME按键处理方法:

一:按键逻辑直接写在keyPressed()里

优点:测试时经常使用,对于短小程序编写速度快。

缺点:需要在keyPressed()里再写个switch(gameState)状态机,这样的缺点估计地球人都知道了。而且将逻辑运算写进keyPressed()里影响keyPressed()的响应。

二:将keyPressed()里的键值提取,在需要的地方做判断。

基本上现在手机游戏编写都使用这种方法了,实现方式也千变万化,最简单的就是定义一个curKey变量,在keyPressed()里将其赋值,在keyReleased()里将其清空,在updateState()里判断该变量的值。这里需要一个keyCode表来对应curKey是什么键,类似这样:

public static final int PADDLE_UP = 1;

public static final int PADDLE_DOWN = 6;

public static final int PADDLE_LEFT = 2;

public static final int PADDLE_RIGHT = 5;

public static final int PADDLE_FIRE = 20;

public static final int PADDLE_SOFT1 = 21;

public static final int PADDLE_SOFT2 = 22;

public static final int PADDLE_SOFT3 = 23;

演化而来的在波斯王子里由于需要判断连续按键而引入了按键状态的概念:

public static final byte Up_Instant = -1;//瞬间抬起,中间过度状态

public static final byte Up_Continuous = 0;//持续抬起,无按键

public static final byte Dn_Instant = 1;//瞬间按下,走

public static final byte Dn_Continuous = 2;//持续按下,跑

public static final byte Dn_Continuous2 = 3; //连击两下,滚

这种处理方式需要每帧里都更新按键状态,键被按下在第一帧为Dn_Instant瞬间按下,在第二帧变为Dn_Continuous持续按下。这种按键处理方式在CoCoMo的引擎里使用了很长一段时间,估计SF的兄弟们现在还在使用着这种方式。他最大的缺点是在Dn_Instant转Dn_Continuous时容易出错。

到了彩虹六号和Medieval Combat时因为在短时间内需要判断连续不同按键来发大招,所以按键处理引入了虚拟按键的概念:

public static final int gk_UP = 1;

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_LSOFT = 1<<16;

public static final int gk_RSOFT = 1<<17;

public static final int gk_MSOFT = 1<<18;

在一定时间内用mask对curKey做掩码就可以判断是否按下了一组特定键,时间过了就清空curKey。

CoCoMo因为厌烦每个机型上都需要一个不同的keyCode表,所以CoCoMo用getGameAction()和Canvas自带的keyCode表,只需要一个keyConvert()将按键转换到CoCoMo自定义的keyCode表即可,这个自定义的keyCode表在每个机型上都是一样的:

public static final byte KEY_NONE = -1;

public static final byte KEY_0 = 0;

public static final byte KEY_UL = 1;

public static final byte KEY_U = 2;

public static final byte KEY_UR = 3;

public static final byte KEY_L = 4;

public static final byte KEY_ATTACK = 5;

public static final byte KEY_R = 6;

public static final byte KEY_DL = 7;

public static final byte KEY_D = 8;

public static final byte KEY_DR = 9;

public static final byte KEY_STAR = 10;

public static final byte KEY_POUND = 11;

public static final byte KEY_SOFT1 = 12;

public static final byte KEY_SOFT2 = 13;

这样可以免去移植之苦,对于某些机型例如S700不支持getGameAction()的问题,CoCoMo用此种方法来解决:

try { //解决getGameAction不被支持的情况

keyCode = s_game.getGameAction(code);

}

catch(Exception e) {

keyCode = CRes.KEY_NONE;

}

不支持的时候会抛出一个异常,让keyCode不做转换即可。哈哈。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有