我举个例子:有这样一个游戏角色移动的游戏,需要角色具有八方向移动,如果用户先按下←键,游戏角色向左移动,这时候用户又按下↓键(←键不抬起),这时候游戏角色要向左下角移动,接下来,如果用户抬起↓键(←键不抬起),游戏角色转为继续左行,如果用户抬起←键(↓键不抬起),游戏角色转为继续下行。同样的,向上,向右按键也是类似的需求,而且这时候,如果用户按下了其它的按键,或按下多于三个光标键时,最后按下的键要忽略。
对于这种涉及复合键的处理,大家可以写一个试试是否容易,或者说是否足够完美。
这就是今天想说的内容,也是我在Flash 游戏开发中对按键控制的一点小经验,希望能对从事Flash游戏开发的同行们有所帮助。
一、先熟悉一下与制作按键相关的事件和语法
1).Key 类
A).Key类的事件
i) onKeyDown = function() {}
当按下某按键时获得通知。同时只能由一个按键触发,如果有多个按键按下,以先后次序触发。若要使用 onKeyDown
,必须创建一个侦听器对象。然后可以为 onKeyDown
定义一个函数,并使用 addListener()
向 Key 对象注册该侦听器,如下面的示例所示:
keyListener.onKeyDown = function () {
trace( " DOWN -> Code: " + Key.getCode() + " \tACSII: " + Key.getAscii() + " \tKey: " + chr(Key.getAscii()));
};
keyListener.onKeyUp = function () {
trace( " UP -> Code: " + Key.getCode() + " \tACSII: " + Key.getAscii() + " \tKey: " + chr(Key.getAscii()));
};
Key.addListener(keyListener);
ii) .onKeyUp = function() {}
当释放某按键时获得通知。同时只能由一个按键触发,如果有多个按键按下后再抬起,以最后按下的键触发。若要使用 onKeyUp
,必须创建一个侦听器对象。然后可以为 onKeyUp
定义一个函数,并使用 addListener()
向 Key 对象注册该侦听器,示例同上。
B).Key类的方法
如果按下 keycode 中指定的键,则返回
true
;否则返回
false
。
如:
if (Key.isDown(Key.RIGHT)) {
this ._x += 10 ;
} else if (Key.isDown(Key.LEFT)) {
this ._x -= 10 ;
}
};
常见 keycode(是Key类的静态属性):
修饰符 | 属性 | 说明 |
---|---|---|
|
| Backspace 键的键控代码值 (8)。 |
|
| Caps Lock 键的键控代码值 (20)。 |
|
| Ctrl 键的键控代码值 (17)。 |
|
| Delete 键的键控代码值 (46)。 |
|
| 下箭头键的键控代码值 (40)。 |
|
| End 键的键控代码值 (35)。 |
|
| Enter 键的键控代码值 (13)。 |
|
| Esc 键的键控代码值 (27)。 |
|
| Home 键的键控代码值 (36)。 |
|
| Insert 键的键控代码值 (45)。 |
|
| 左箭头键的键控代码值 (37)。 |
|
| 一个引用列表,引用对象是向 Key 对象注册的所有侦听器对象。 |
|
| Page Down 键的键控代码值 (34)。 |
|
| Page Up 键的键控代码值 (33)。 |
|
| 右箭头键的键控代码值 (39)。 |
|
| Shift 键的键控代码值 (16)。 |
|
| 空格键的键控代码值 (32)。 |
|
| Tab 键的键控代码值 (9)。 |
|
| 上箭头键的键控代码值 (38)。 |
其它的字母键并没有定义成静态属性,需要使用数字的键控代码值来使用,有人写了一个所有按键的Key类,我复制在下边,可做参考:


public class Key {
public static const VK_1:uint = 49;
public static const VK_2:uint = 50;
public static const VK_3:uint = 51;
public static const VK_4:uint = 52;
public static const VK_5:uint = 53;
public static const VK_6:uint = 54;
public static const VK_7:uint = 55;
public static const VK_8:uint = 56;
public static const VK_9:uint = 57;
public static const VK_0:uint = 48;
public static const VK_A:uint = 65;
public static const VK_B:uint = 66;
public static const VK_C:uint = 67;
public static const VK_D:uint = 68;
public static const VK_E:uint = 69;
public static const VK_F:uint = 70;
public static const VK_G:uint = 71;
public static const VK_H:uint = 72;
public static const VK_I:uint = 73;
public static const VK_J:uint = 74;
public static const VK_K:uint = 75;
public static const VK_L:uint = 76;
public static const VK_M:uint = 77;
public static const VK_N:uint = 78;
public static const VK_O:uint = 79;
public static const VK_P:uint = 80;
public static const VK_Q:uint = 81;
public static const VK_R:uint = 82;
public static const VK_S:uint = 83;
public static const VK_T:uint = 84;
public static const VK_U:uint = 85;
public static const VK_V:uint = 86;
public static const VK_W:uint = 87;
public static const VK_X:uint = 88;
public static const VK_Y:uint = 89;
public static const VK_Z:uint = 90;
public static const VK_F1:uint = 112;
public static const VK_F2:uint = 113;
public static const VK_F3:uint = 114;
public static const VK_F4:uint = 115;
public static const VK_F5:uint = 116;
public static const VK_F6:uint = 117;
public static const VK_F7:uint = 118;
public static const VK_F8:uint = 119;
public static const VK_F9:uint = 120;
public static const VK_F10:uint = 121;
public static const VK_F11:uint = 122;
public static const VK_F12:uint = 123;
public static const VK_F13:uint = 124;
public static const VK_F14:uint = 125;
public static const VK_F15:uint = 126;
/* numpad */
public static const VK_NUMPAD_0:uint = 96;
public static const VK_NUMPAD_1:uint = 97;
public static const VK_NUMPAD_2:uint = 98;
public static const VK_NUMPAD_3:uint = 99;
public static const VK_NUMPAD_4:uint = 100;
public static const VK_NUMPAD_5:uint = 101;
public static const VK_NUMPAD_6:uint = 102;
public static const VK_NUMPAD_7:uint = 103;
public static const VK_NUMPAD_8:uint = 104;
public static const VK_NUMPAD_9:uint = 105;
public static const VK_NUMPAD_MULTIPLY:uint = 106;//*
public static const VK_NUMPAD_ADD:uint = 107;//+
public static const VK_NUMPAD_ENTER:uint = 108;//enter
public static const VK_NUMPAD_SUBTRACT:uint = 109;//-
public static const VK_NUMPAD_DECIMAL:uint = 110;//.
public static const VK_NUMPAD_DIVIDE:uint = 111;///
public static const VK_BACKSPACE:uint = 8;//backspace
public static const VK_TAB:uint = 9;//tab
public static const VK_ENTER:uint = 13;//main ENTER
public static const VK_SHIFT:uint = 16;//shift
public static const VK_CONTROL:uint = 17;//ctrl
public static const VK_ESCAPE:uint = 27;//esc
public static const VK_SPACE:uint = 32;//space
public static const VK_CAPS_LOCK:uint = 20;//caps lock
public static const VK_NUM_LOCK:uint = 144;//num lock
public static const VK_SCROLL_LOCK:uint = 145;//scroll lock
public static const VK_PAUSE:uint = 19;//pause / break
public static const VK_PAGE_UP:uint = 33;//page up
public static const VK_PAGE_DOWN:uint = 34;//page down
public static const VK_END:uint = 35;//end
public static const VK_HOME:uint = 36;//home
public static const VK_INSERT:uint = 45;//insert
public static const VK_DELETE:uint = 46;//delete
public static const VK_LEFT:uint = 37;//left arrow
public static const VK_UP:uint = 38;//up arrow
public static const VK_RIGHT:uint = 39;//right arrow
public static const VK_DOWN:uint = 40;//down arrow
public static const VK_WINDOWS:uint = 91;//windows
public static const VK_MENU:uint = 93;//menu
}
ii) Key.getCode 方法
返回按下的 最后一个键的键控代码值,并且不会区分字母的大小字,即使用此方法时,任何一个按键,只有一个Code值。
2).MovieClip的事件
i) MovieClip.onKeyDown
当影片剪辑 具有输入焦点并且用户按下某个键时调用。
ii) MovieClip.onKeyUp
当释放按键时调用。仅当影片剪辑的输入焦点被启用和设置后,
onKeyUp
事件处理函数才能起作用。即要求影片剪辑
具有输入焦点。二、Flash中对按键捕获处理,拔开按键的迷雾
1).Flash中,如果你使用Key.onKeyDown 事件侦听器,则不管焦点在Flash内的那个对象上,按键均能被捕获,这里有一种情况,当先后按下多个键(二个以上的按键)时,onKeyDown事件是按先后次序触发的,而onKeyUp事件只能由最后按下的键触发。举例:
我先按下A键,再接着按下S键,同时A键不抬起,则这时候,onKeyDown先被A键触发一次,接着被S键触发一次,而这时候,不管你把那个键抬起, onKeyUp事件始终是由最后按下的那个键触发的。这点一定要注意,这时候A键的onKeyUp事件已经被后按的键“冲”掉了,就算抬起A键,onKeyUp也不会被触发。可以使用本文开头那段代码测试就知道了。
2).使用 Key.isDown,可以知道有那些键被按下,不管按键的先后(其实是有先后的,只是先后时间差别太小,isDown方法并判断不出先后次序,要判断次序,需要借助其它方法),只要按下,此方法就能检测出,如:


var keyListener:Object = new Object();
keyListener.onKeyDown = function() {
trace("DOWN -> Code: "+Key.getCode()+"\tACSII: "+Key.getAscii()+"\tKey: "+chr(Key.getAscii()));
if (Key.isDown(65)) {
trace("按下a键");
}
if (Key.isDown(83)) {
trace("按下s键");
}
if (Key.isDown(68)) {
trace("按下d键");
}
if (Key.isDown(70)) {
trace("按下f键");
}
};
keyListener.onKeyUp = function() {
trace("UP -> Code: "+Key.getCode()+"\tACSII: "+Key.getAscii()+"\tKey: "+chr(Key.getAscii()));
};
Key.addListener(keyListener);
当你先后同时按下a,s,d,f这四个键时,都会被检测到。
利用这点,我们就可以制作游戏中的复合键,比如八方向键,或快捷键,如Ctrl+F等。
3).如果同时按下了多个键,那么如何知道先后次序呢?
还记得 Key. getCode的用法说明吗?“返回按下的最后一个键的键控代码值”,同样的,此方法也不能获得按键的先后次序,但是它可以获得最后一个按键,使用它的这一特性,我们可以写出自己的检测类,用来当按下多键时,检测按键的次序。如:


var keyList:String = "按键次序:";
var keyListener:Object = new Object();
keyListener.onKeyDown = function() {
trace("DOWN -> Code: "+Key.getCode()+"\tACSII: "+Key.getAscii()+"\tKey: "+chr(Key.getAscii()));
if (Key.isDown(65)) {
trace("按下a键");
}
if (Key.isDown(83)) {
trace("按下s键");
}
if (Key.isDown(68)) {
trace("按下d键");
}
if (Key.isDown(70)) {
trace("按下f键");
}
//总是把最后的按键,添加在按键列表中,如果列表中已存在,就不添加,注意不可见按键得变换方法,如光标键
if (keyList.indexOf(chr(Key.getAscii()), 0)<0) {
keyList += chr(Key.getAscii());
}
trace(keyList);
};
keyListener.onKeyUp = function() {
trace("UP -> Code: "+Key.getCode()+"\tACSII: "+Key.getAscii()+"\tKey: "+chr(Key.getAscii()));
};
Key.addListener(keyListener);
使用此段代码,你可以尝试着同时按下a,s,d,f键,可以看看按键次序。
4).其实Flash按键的难于处理,主要是在于复合键的处理上,在多复合键中,如果用户有意按下多键,如何抛弃或“不理睬”不想关注的按键呢?
比如光标键吧,我们想在按下左光标+上光标键时,人物向左上角斜方向移动,那如果这时候,用户又按下向下的光标键呢,或者又按了其它的字母键呢?这时候往往会出现我们不想要的结果。即最后按键会干扰已按下的组合键。处理这种情况,除了写较复杂的if判断之外,就可以使用上边说的检测按键次序,这样只有前两个按键有效,后边再按下的键就无效,从而达到控制的目的。
5).其实很多时候,我们是通过光标控制一个MovieClip的移动的,那么如果在此使用MovieClip的按键事件下处理按键,就要注意MovieClip是与焦点相关的,如果有多个对象,那就得处理焦点一定在要移动的对象上头,按键才有效,除此之外,它的按键事件使用原理同Key的按键事件原理,所以大多数时候,我们并不使用MovieClip的按键事件,而改用MovieClip.onEnterFrame来侦听按键。下边我给了一个示例,就是使用的这个方法。
三、八方向按键示例 新窗口打开>>
四、八方向按键源码下载
点此下载(6K)>>