All user input is captured by the engine and dispatched as actions to script- and GUI script components in game objects that have acquired input focus and that implement the on_input()
function. This manual explains how you set up bindings to capture input and how you create code that responds to it.
The input system uses a set of simple and powerful concepts, allowing you to manage input as you see fit for your game.
The input bindings is a project wide table that allows you to specify how device input should translate into named actions before they are dispatched to your script components and GUI scripts. You can create a new input binding file, right click a location in the Assets view and select New... ▸ Input Binding. To make the engine use the new file, change the Game Binding entry in game.project.
A default input binding file is automatically created with all new project templates so there is usually no need to create a new binding file. The default file is called “game.input_binding” and can be found in the “input” folder in the project root. Double click the file to open it in the editor:
To create a new binding, click the + button at the bottom of the relevant trigger type section. Each entry has two fields:
jump
. Note that there is a known bug where touch inputs unfortunately cannot have the same action names as other inputs.There are five device specific types of triggers that you can create:
In addition to the five different trigger types listed above Defold also supports accelerometer input in native Android and iOS applications. Check the Use Accelerometer box in the Input section of your game.project file.
function on_input(self, action_id, action)
if action.acc_x and action.acc_y and action.acc_z then
-- react to accelerometer data
end
end
To listen to input actions in a script component or GUI script, the message acquire_input_focus
should be sent to the game object holding the component:
-- tell the current game object (".") to acquire input focus
msg.post(".", "acquire_input_focus")
This message instructs the engine to add input capable components (script components, GUI components and collection proxies) in the game objects to the input stack. The game object components are put on top of the input stack; the component that is added last will be top of the stack. Note that if the game object contains more than one input capable component, all components will be added to the stack:
If a game object that has already acquired input focus does so again, its component(s) will be moved to the top of the stack.
Input actions are dispatched according to the input stack, from the top to the bottom.
Any component that is on the stack containing an on_input()
function will have that function called, once for each input action during the frame, with the following arguments:
self
action_id
action
pressed
etc. See on_input() for details on the available action fields.function on_input(self, action_id, action)
if action_id == hash("left") and action.pressed then
-- move left
local pos = go.get_position()
pos.x = pos.x - 100
go.set_position(pos)
elseif action_id == hash("right") and action.pressed then
-- move right
local pos = go.get_position()
pos.x = pos.x + 100
go.set_position(pos)
end
end
Each game world that is dynamically loaded through a collection proxy has its own input stack. For action dispatch to reach the loaded world’s input stack, the proxy component must be on the main world’s input stack. All components on a loaded world’s stack are handled before dispatch continues down the main stack:
It is a common error to forget to send acquire_input_focus
to the game object holding the collection proxy component. Skipping this step prevents input from reaching any of the components on the loaded world’s input stack.
To stop listening to input actions, send a release_input_focus
message to the game object. This message will remove any of the game object’s components from the input stack:
-- tell the current game object (".") to release input focus.
msg.post(".", "release_input_focus")
A component’s on_input()
can actively control whether actions should be passed on further down the stack or not:
on_input()
returns false
, or a return is omitted (this implies a nil
return which is a false value in Lua) input actions will be passed on to the next component on the input stack.on_input()
returns true
input is consumed. No component further down the input stack will receive the input. Note that this applies to all input stacks. A component on a proxy-loaded world’s stack can consume input preventing components on the main stack to receive input:There are many good use cases where input consumption provides a simple and powerful way to shift input between different parts of a game. For example, if you need a pop-up menu that temporarily is the only part of the game that listens to input:
The pause menu is initially hidden (disabled) and when the player touches the “PAUSE” HUD item, it is enabled:
function on_input(self, action_id, action)
if action_id == hash("mouse_press") and action.pressed then
-- Did the player press PAUSE?
local pausenode = gui.get_node("pause")
if gui.pick_node(pausenode, action.x, action.y) then
-- Tell the pause menu to take over.
msg.post("pause_menu", "show")
end
end
end
The pause menu GUI acquires input focus and consumes input, preventing any input other than what’s relevant for the pop-up menu:
function on_message(self, message_id, message, sender)
if message_id == hash("show") then
-- Show the pause menu.
local node = gui.get_node("pause_menu")
gui.set_enabled(node, true)
-- Acquire input.
msg.post(".", "acquire_input_focus")
end
end
function on_input(self, action_id, action)
if action_id == hash("mouse_press") and action.pressed then
-- do things...
local resumenode = gui.get_node("resume")
if gui.pick_node(resumenode, action.x, action.y) then
-- Hide the pause menu
local node = gui.get_node("pause_menu")
gui.set_enabled(node, false)
-- Release input.
msg.post(".", "release_input_focus")
end
end
-- Consume all input. Anything below us on the input stack
-- will never see input until we release input focus.
return true
end
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB