In Trial getting inputs from the user is divided up into three parts: raw input events, actions, and mappings.
Raw device inputs are delivered via the event system. Each class of device has its own events derived from
Trial's systems allow distinguishing between multiple gamepads, but not between multiple keyboards or mice.
You should almost never have to directly interface with these events, as they are not user-configurable. Instead, you should use the input mapping system.
Input events are provided by the rendering backend and cl-gamepad, and should automatically appear in the
scene of your
actions are abstract events that correspond to in-game actions. Actions are typically mapped from existing events, and you can look at the origin with
source-event. New actions are defined with
define-action. The superclass list is used to attach the event to one or more
action-sets are ways to group actions together under a set that allows you to activate and deactivate all actions at once. This way you can have a separate sets of actions for menu navigation, for in-game, etc. Sets can be activated by setting
active-p. An action will be active as long as at least one of the sets it is a subclass of is active.
Often it's also desired to have
action-sets be mutually exclusive. In that case, making the sets a subclass of
exclusive-action-set will ensure all others will be automatically deactivated when another is activated.
Most actions will represent some kind of event request, such as "jump", "interact", "select next", "confirm", etc. For some games however it can also make more sense to have actions that carry a value, such as "gas" or "camera tilt". For the latter, the superclasses
spatial-action are useful.
Actions by themselves allow you to define player input with a layer of abstraction, but they won't be useful unless actions can be fired by user inputs. This is where the mapping layer comes into play.
Event mappings are executed through
map-event, which is handled by the
controller when it is present in the scene. If you do not have a controller present, you should call
map-event yourself somehow.
Defining how events are mapped is, in the most generic way, done via
define-mapping-function. The function it defines is invoked for each event, and can then just issue other events back onto the loop. Typically though this is too generic and open-ended, and also doesn't allow players to customise how the mapping works.
keymap.lisp file should be defined, which describes the mappings. This file will contain all the default mappings present, and Trial will emit a new file of the same structure when the user changes the mappings. Trial will also take care of keeping track of the action's state: whether it is currently being
retained or not. Often it is much more useful to be able to ask what the action's retained state is. For digital actions this means whether it's "active" or not. For others it's what the last value, position, or location was.
The file describing action mappings is in s-expression format and contains definitions like this:
(trigger jump (key :one-of (:space)) (button :one-of (:b :a)))
Meaning: when the
:space key is pressed, or when the
:a button on a gamepad is pressed, fire a
The possible mapping types are
trigger for digital maps, and
bind for analogue or directional maps.
The possible binding sources are
key for keyboard keys,
button for gamepad buttons,
axis for gamepad axes, and
mouse for mouse buttons. Each of the bindings also accepts the following parameters:
:one-of the qualifiers to look out for, typically the names of the buttons
:threshold the value at which the input becomes "active". Defaults to 0.5, but only used for
:toggle if NIL (default) then the action is retained while the input is "active". Otherwise the action stays retained until the input becomes "inactive" and then "active" again. Only used for
:value what value should be used for the action when the input is "active". Only used for
bind mappings on non-
Querying and interacting with the mappings can of course also be done programmatically outside of the
keymap.lisp source file. On the most basic, one can
save-mapping to interact with the file. Finding mappings that spawn an action can be done via
find-action-mappings. It can also be useful to capture an input event and turn that into on
action-mapping or vice-versa. To do so, simply use
event-to-action-mapping, or the inverse,
Sometimes, particularly when switching action sets, it can be useful to reset or clear retentions.
clear-retained will reset all retention information.
reset-retained will attempt to "back fill" retention information based on current device state.
It can also be useful to inhibit mapping of any key events, such as when the user is typing into a text field, as then key presses could instead lead to unintended actions being taken. To control the mapping simply set
Finally, default retentions for all mouse buttons and keyboard keys are kept. The retention is simply named after the key or button. These retentions can be useful for debugging purposes.