-
Notifications
You must be signed in to change notification settings - Fork 8
Controls
Elation Engine supports a system for mapping actions to input events in a generic fashion. Applications define named actions, such as "move_forwards", "turn_left", "jump", "shoot", etc. and then the input handling system can bind these to any input device.
When writing your app, you can create any number of control contexts, which can be activated and deactivated on the fly. For instance, you might define a control context for your game's menu system which is always active, and then you have a set of contexts for objects which your player controls in-game, like a vehicle or a turret. The game's menu system context would always be active, but the other contexts could be enabled or disabled depending on where the player is and what they're interacting with.
var client_state = controls.addContext('client', {
'load_url': { onpress: elation.bind(this, this.showLoadURL) },
'show_menu': { onpress: elation.bind(this, this.showMenu) }
});
var vehicle_state = controls.addContext('player_vehicle', {
'steer_left': { onpress: elation.bind(this, this.updateControls) },
'steer_right': { onpress: elation.bind(this, this.updateControls) },
'accelerate': { onpress: elation.bind(this, this.updateControls) },
'brake': { onpress: elation.bind(this, this.updateControls) }
});
controls.activateContext('client');
// Create a car, and attach events which activate and deactivate the car's control context
var mycar = createCar();
elation.events.bind(mycar, 'player_enter', function() { controls.activateContext('player_vehicle'); });
elation.events.bind(mycar, 'player_leave', function() { controls.deactivateContext('player_vehicle'); });
In order to support a wide variety of controller types, we'll need to be able to define mappings which can be applied for different controller types. Some examples of different types of controllers:
- XBox 360/One (gamepad)
- PS3/PS4 (gamepad)
- Oculus Touch (motion controller)
- HTC Vive (motion controller)
- Logitech G25/G27 (steering wheel)
- QWERTY/AZERTY/Dvorak (keyboard)
- Mice
- Leap Motion (hand tracking)
Each of these devices has its own unique button layout, and we need to have a way of mapping a player's inputs to the named actions defined above. They each also have their own physical representation which we'd like to show, and a set of glyphs which represent each individual button on the controller, which can be used for context menus. We want our device definitions to encapsulate all of these, and allow users to remap commands on the fly to suit their preferences and needs. So we want to set up a mapping between the physical button/axis numbers and their logical names.
Here's a list of base names which controllers should try to map to as much as makes sense. Controllers can also define any number of custom names that make sense for the functions they provide.
{
'axes' : [
'Left_Stick_X',
'Left_Stick_Y',
'Right_Stick_X',
'Right_Stick_Y'
],
'buttons' : [
'A_Button',
'B_Button',
'X_Button',
'Y_Button',
'Left_Stick_Button',
'Right_Stick_Button',
'Start_Button',
'Back_Button',
'Home_Button',
'DPad_Up',
'DPad_Down',
'DPad_Left',
'DPad_Right',
'Left_Trigger0',
'Right_Trigger0',
'Left_Trigger1',
'Right_Trigger1'
]
}
Here's how we map the physical buttons to these names:
{
"name": "Oculus Touch (Left)",
"model": "controllers/oculus/touch-left.gltf",
"identifier": "Oculus Touch (Left)",
"hasPosition": true,
"hasOrientation": true,
"bindings": {
"axes": {
"Left_Stick_X": 0,
"Left_Stick_Y": 1
},
"buttons" : {
"X_Button": 4,
"Y_Button": 5,
"Left_Stick_Button": 1,
"Left_Trigger0": 2,
"Left_Trigger1": 3
}
}
},
{
"name": "Oculus Touch (Right)",
"model": "controllers/oculus/touch-right.gltf",
"identifier": "Oculus Touch (Right)",
"hasPosition": true,
"hasOrientation": true,
"bindings": {
"axes": {
"Right_Stick_X": 0,
"Right_Stick_Y": 1
},
"buttons" : {
"A_Button": 4,
"B_Button": 5,
"Right_Stick_Button": 1,
"Right_Trigger0": 2,
"Right_Trigger1": 3
}
}
},
{
"name": "Oculus Remote",
"model": "controllers/oculus/remote.gltf",
"identifier": "Oculus Remote",
"hasPosition": false,
"hasOrientation": false,
"bindings": {
"axes": {
},
"buttons" : {
"A_Button": 0,
"B_Button": 1,
"DPad_Up": 2,
"DPad_Down": 3,
"DPad_Left": 4,
"DPad_Right": 5
}
}
}
Now that we have a set of actions that the game exposes, and a set of controllers that the engine understands, all we need is a simple config to bind them together. The game developer should provide a default config, and then users should be able to override that config either through an interface or by loading an external file/URL. Controller config overrides should be stored in localStorage.
{
"Left_Stick_X": "move_sideways",
"Left_Stick_Y": "move_forward",
"Right_Stick_X": "look_yaw",
"Right_Stick_Y": "look_pitch",
"Right_Trigger0": "fire_weapon",
"Right_Trigger1": "grab_right",
"Left_Trigger1": "grab_left",
"Button_A": "jump",
"Button_B": "reload",
"Keyboard_W": "move_forward",
"Keyboard_A": "move_left",
"Keyboard_S": "move_back",
"Keyboard_D": "move_right",
"Keyboard_Ctrl": "fire_weapon",
"Keyboard_Space": "jump",
"Keyboard_R": "reload",
"Keyboard_S": "move_back",
"Keyboard_D": "move_right",
"Mouse_Button0": "fire_weapon",
"Mouse_X": "look_yaw",
"Mouse_Y": "look_pitch",
}