Input tutorial

The engine can handle input from a mouse, keyboard or joystick. To determine what input devices are available, your script should check whether the global variables "keyboard", "mouse" and "joystick" have non-nil values. When more than one joystick is attached to the user's system, the first one to be enumerated is used.

Input events

Input device objects raise events whenever one of their buttons is pressed, released or when one of their axes is moved. Our program can react to those events by registering a handler function. Let's try to write a simple script that creates a new window and destroys it when the user presses the escape key. As you see, the script is self-explanatory. The only tricky part is the syntax for assigning a handler function to the "on_press" event. You should be aware of the number of arguments that the handler function is supposed to accept. In this case, the "on_press" event has just one argument - the key that was pressed.

display:create ( "Press escape to quit", 640, 480, 32, true )

if keyboard then
  keyboard.on_press = function ( keyboard, key )
    if key == KEY_ESCAPE then
      display:destroy ( )
Download:  inputevent.lua

Polling input devices

Another way of handling input is by periodically polling the input device for changes. In the following example, we will use a timer to poll the keyboard and check if any of the arrow keys are pressed. We will then move a little blue square in the direction of the pressed arrow key. If you understand how timers work, this script should look trivial to you.

display:create ( "Polling input devices", 640, 480, 32, true )

square = Sprite ( )
square.canvas:rectangle ( 30, 30 )
square.canvas:set_fill_style ( BLUE, 1 )
square.canvas:fill ( )
display.viewport:add_child ( square )

timer = Timer ( )
timer:start ( 16, true )
timer.on_tick = function ( timer )
  if keyboard:is_down ( KEY_UP ) then
    square.y = square.y + 1
  elseif keyboard:is_down ( KEY_DOWN ) then
    square.y = square.y - 1
  if keyboard:is_down ( KEY_LEFT ) then
    square.x = square.x - 1
  elseif keyboard:is_down ( KEY_RIGHT ) then
    square.x = square.x + 1
Download:  polling.lua

Notice that the script does not take the timer's delta values into account. Ideally, the blue square should move 1 pixels every 16 milliseconds. But as you should know, the "on_tick" event is never guaranteed to occur at precisely the desired interval. Any sort of lag and this event will be raised less frequently than once every 16 milliseconds. Therefore, the square might move at different speeds on different machines. To achieve frame-independent motion, we shouldn't just change the sprite's position by 1, but by 1 * timer:get_delta ( ). Delta measures how many intervals have elapsed since the last callback. It is calculated by dividing the actual time elapsed between callbacks by the preset timer interval and can never be less than 1.

Mouse input

The 'xaxis' and 'yaxis' properties of the mouse object reflect the current position of the system cursor. The cursor position is measured in pixels where the center of the window serves as the origin (0, 0) with the X and Y axes increasing in the up and right directions. To illustrate how the coordinate system of the mouse is set up, we're going to look at an example script. The following code creates a new sprite and writes on it the current cursor position.

display:create ( "Mouse input", 640, 480, 32, true )

my_font = Font ( )
my_font:load_system ( "Arial", 18 )

my_sprite = Sprite ( )
display.viewport:add_child ( my_sprite )

mouse.on_move = function ( mouse, dx, dy )
  my_sprite.canvas:clear ( )
  my_sprite.canvas:move_to ( mouse.xaxis, mouse.yaxis )
  my_sprite.canvas:set_font ( my_font )
  my_sprite.canvas:write ( mouse.xaxis .. " " .. mouse.yaxis )
Download:  mouse.lua