输入处理
用户通过鼠标、键盘或者手柄等输入设备与jME3应用程序进行交互。我们使用SimpleApplication中的inputManager来响应用户输入。
下面是给游戏添加交互的步骤:
- 给每个action选择一个或多个触发器(trigger),例如键盘、鼠标点击等;
- 给每个action添加一个从trigger到inputManager间的映射;
- 在SimpleApplication中创建至少一个监听;
- 将每个action的映射(步骤2中提到的)注册给监听器;
- 在监听中实现每个action的具体内容。
代码样例
TestControls.java
@Override
public void simpleInitApp() {
// 1.选择触发器:空格和鼠标滑轮
// 2.建立映射
inputManager.addMapping("My Action",
new KeyTrigger(KeyInput.KEY_SPACE),
new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
// 3.创建监听
// 4.给监听注册mappings
inputManager.addListener(actionListener, "My Action");
inputManager.addListener(analogListener, "My Action");
}
// 5.在监听中实现action
private ActionListener actionListener = new ActionListener(){
public void onAction(String name, boolean pressed, float tpf){
System.out.println(name + " = " + pressed);
}
};
public AnalogListener analogListener = new AnalogListener() {
public void onAnalog(String name, float value, float tpf) {
System.out.println(name + " = " + value);
}
};
TestJoystick.java
1.选择触发器(Trigger)
为交互选择一个或多个触发事件。我们使用com.jme3.input.controls包中的KeyTrigger,MouseAxisTrigger,MouseButtonTrigger,JoyAxisTrigger和JoyButtonTrigger。
MouseAxis和JoyAxis沿着x轴(左/右)和y轴(上/下)。这两个触发器多了一个布尔型参数,false代表负半轴,即左和下。记得在监听时写上正半轴和负半轴。
2.删除默认触发器映射
inputManager.deleteMapping( SimpleApplication.INPUT_MAPPING_MEMORY );
3.添加自定义触发器
在初始化应用的时候,给每个触发器添加一个映射。
给映射一个有意义的名字。这个名字需要能反映出action本身,而不是所按的按键,比如:
inputManager.addMapping("Pause Game", new KeyTrigger(KeyInput.KEY_P));
inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE));
...
下面的例子介绍了如何给一个action添加多个触发器。例如,有的用户喜欢用wasd键控制方向,而有的则喜欢用方向键。用逗号分开每个触发器:
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A),
new KeyTrigger(KeyInput.KEY_LEFT)); // A and left arrow
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D),
new KeyTrigger(KeyInput.KEY_RIGHT)); // D and right arrow
...
4. 创建监听
jME3提供两种输入监听:AnalogListener和ActionListener。同一个应用中你可以使用一个也可以两个都使用.
这两个输入监听不知道也不在乎那个键被点击,他们只知道被出发的映射的名称(named input mapping)。
ActionListener
- 用于监听确切的“按键点击或松开”动作。
- 例如:暂停/开始,用步枪或左轮枪涉及,跳,点击选择。
- jME3可以访问的是:
- 触发动作的名称
- 代表是否仍在点击或已经松开的布尔值
- 当前每帧时间的浮点数
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean keyPressed, float tpf) {
/** TODO: test for mapping names and implement actions */
}
};
AnalogListener
- 用于持续动作
- 例如:走路、跑、旋转、加速车辆、扫射、半自动武器射击
- jME3可以访问的是:
- 触发动作的名称
- 代表是否仍在点击或已经松开的布尔值
- 当前每帧时间的浮点数
private AnalogListener analogListener = new AnalogListener() {
public void onAnalog(String name, float keyPressed, float tpf) {
/** TODO: test for mapping names and implement actions */
}
};
5.给监听注册映射
要想激活映射,必须将其注册给监听。在添加mappings到inputManager的代码块后面注册监听。
在下面的例子中,将把“Pause Game”注册给actionListener对象。
inputManager.addListener(actionListener, new String[]{"Pause Game"});
在下面的例子中,将把方向mappings注册给analogLisioner对象,因为走路时持续的过程,用户需要一直按着按键。
inputManager.addListener(analogListener, new String[]{"Left", "Right"});
如你所见,可以用数组的方式将多个动作加到一个监听里。这样可以让代码整洁。
6. 实现监听
将具体的action写到监听的TODO中。最典型的,写一系列if/else条件语句,判断映射名称,然后调用相应的action。
注意if和else if的区别。
- 如果一些action可以被同时触发,则使用一系列“if”。例如,一个角色可以向前跑也可以同时向左跑。
- 如果action间相互排斥,则使用else if,这样其他的就会被跳过。比如射击和捡东西,只能同时满足一个。
ActionListener
一般来讲,你希望一个action只在按下按键或松开按键是被触发一次。比如,点某个键后开门,或者捡起一个东西。这些情况下,使用ActionListener,并且加一个&&!keyPressed语句,如下。
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("Pause Game") && !keyPressed) { // test?
isRunning = !isRunning; // action!
}
if ...
}
};
AnalogListener
下面的例子展示了如何用AnalogListener定义action。这些动作被持续触发,只要按键或鼠标被点击。该监听可以被用于半自动武器射击和方向导航。
private AnalogListener analogListener = new AnalogListener() {
public void onAnalog(String name, float value, float tpf) {
if (name.equals("Rotate")) { // test?
player.rotate(0, value*speed, 0); // action!
}
if ...
}
};
用户自定义key map
很有可能你的用户使用不同的键盘布局,或者“鼠标反向”,或者喜欢不同于你设定的方向键来控制方向。这时就该设置一个“设置界面”,让用户自定义触发的按键。用变量替代inputManager.addMapping()中的内容,然后在游戏开始时加载这些设置。
分离triggers和mappings的好处在于可以很简单地remap。你的代码只需要删除并添加一些触发器映射,代码核心不变。