All video games have them. We couldn't make a game without event handling. In fact, we couldn't make anything practical to the user without being able to retrieve data from our keyboards, mice and controllers, but how we process that data is then up to us.

In Kha, we are typically presented with listeners, which are function bindings to underlying APIs that call out to us whenever the user performs an action. If we were in an object oriented scenario, the number of listeners we may have could grow and become increasingly complex. Twinspire handles all of these listeners automatically when we create an Application, eliminating duplicating functions and listeners for all event handling. We use twinspire.events.Event and corresponding APIs to handle these events accordingly.

This method is the more appropriate method of handling events, especially in video games when we want to respond to user input immediately.

Mouse Movement

We already have the code to store mouse position and other like events, but we just don't do anything with them yet. Let's do that:

function handleEvent(e:Event)
{
    if (e.type == EVENT_MOUSE_MOVE)
    {
        mouseX = e.mouseX;
        mouseY = e.mouseY;
    }
    else if (e.type == EVENT_MOUSE_DOWN)
    {
        mouseDown = true;
    }
    else if (e.type == EVENT_MOUSE_UP)
    {
        mouseDown = false;
        mouseReleased = true;
    }
}

In the above code, we need to check for the type of the event being called. Without doing this, we don't really know what type of action is being made. There are a lot of types of events that exist, but we will not demonstrate them all here. This is purely to demonstrate how the event handling system works.

For the full event API, see the Event class and EventType for all the applicable types that exist.

Once we have checked the type we can do something with that type. With the EVENT_MOUSE_MOVE type, two variables are set which we can use to determine mouse location. These are mouseX and mouseY. We store these as local variables to use later.

We also use a mouseDown and mouseReleased boolean values, which are either true or false depending on whether the mouse button is up or down. We need to make sure we set mouseReleased to false at the end of each frame otherwise we will create a scenario of constant mouse click's:

function render(g2:Graphics)
{
    // our code

    mouseReleased = false;
}

We can additionally handle multiple mouse buttons, which is best done using an Array of boolean values which determines which mouse button is down at any given time.

if (e.type == EVENT_MOUSE_DOWN)
{
    mouseButtonDown[e.mouseButton] = true;
}

We could create a mouseButtonDown with a maximum of 20 values to cover ourselves for all the different types of mice that exist in the world. We can initialise this by doing the following:

mouseButtonDown = [ for (i in 0...20) false ];

The reason the above code works is because Haxe is an expressive language, and thus every time we iterate 20 times in a for loop we set false, which incrementally pushes false into the array on initialisation.

We can then determine which mouse button is down by referring to mouseButtonDown[0] for the first item, i.e. the left mouse button.

This may not be the most appropriate way to determine mouse button's being pressed down. We may just have a single variable for mouseButtonDown which takes an Int, referring to the current mouse button.

List of Events and Types

Here is a list of the events Twinspire handles and what data is allocated inside of the Event class:

  1. EVENT_MOUSE_MOVE
e.mouseX = x;
e.mouseY = y;
e.mouseMovementX = movementX;
e.mouseMovementY = movementY;
  1. EVENT_MOUSE_WHEEL
e.mouseDelta = delta;
  1. EVENT_MOUSE_UP
e.mouseButton = button;
e.mouseX = x;
e.mouseY = y;
  1. EVENT_MOUSE_DOWN
e.mouseButton = button;
e.mouseX = x;
e.mouseY = y;
  1. EVENT_KEY_PRESS
e.char = char;
  1. EVENT_KEY_UP
e.key = key;

If the Control key on the keyboard was previously down, and either the X or C key is released from the keyboard, Twinspire will also register this as a cutTrigger. You can check the cutTriggered inside an EVENT_CLIPBOARD_CUT event type where Twinspire will get the Application.cutData to copy onto the system clipboard. Make sure to set the Application.cutData value to whatever is being "cut" inside this event before the EVENT_CLIPBOARD_CUT is triggered.

Example:

if (e.type == EVENT_KEY_UP)
{
    if (Application.cutTriggered)
    {
        Application.cutData = selectedString;
    }
}
  1. EVENT_KEY_DOWN
e.key = key;
  1. EVENT_MOUSE_LOCK_CHANGE

No data is set.

  1. EVENT_MOUSE_LOCK_ERROR

No data is set.

  1. EVENT_GAMEPAD_AXIS
e.gamepadId = 0;
e.gamepadAxis = axis;
e.gamepadAxisValue = value;

e.gamepadId is a zero-based index value defining which controller moves their axis, if more than one gamepad is plugged in.

Up to four controllers is supported by Twinspire.

  1. EVENT_GAMEPAD_BUTTON
e.gamepadId = 0;
e.gamepadButton = button;
e.gamepadButtonValue = value;

e.gamepadId is a zero-based index value defining which controller presses a button, if more than one gamepad is plugged in.

Up to four controllers is supported by Twinspire.

  1. EVENT_TOUCH_START
e.touchIndex = index;
e.touchX = x;
e.touchY = y;
  1. EVENT_TOUCH_END
e.touchIndex = index;
e.touchX = x;
e.touchY = y;
  1. EVENT_TOUCH_MOVE
e.touchIndex = index;
e.touchX = x;
e.touchY = y;
  1. EVENT_ACCELEROMETER
e.accelerometerX = x;
e.accelerometerY = y;
e.accelerometerZ = z;
  1. EVENT_GYROSCOPE
e.gyroscopeX = x;
e.gyroscopeY = y;
e.gyroscopeZ = z;
  1. EVENT_PEN_DOWN
e.penX = x;
e.penY = y;
e.penPressure = pressure;

As far as Twinspire is aware, PEN_* events do not work on the JavaScript target.

  1. EVENT_PEN_UP
e.penX = x;
e.penY = y;
  1. EVENT_PEN_MOVE
e.penX = x;
e.penY = y;
e.penPressure = pressure;
  1. EVENT_FOREGROUND

No data is set.

  1. EVENT_RESUME

No data is set.

  1. EVENT_PAUSE

No data is set.

  1. EVENT_BACKGROUND

No data is set.

  1. EVENT_SHUTDOWN

No data is set.

  1. EVENT_CLIPBOARD_CUT

No data is set.

  1. EVENT_CLIPBOARD_COPY

No data is set.

  1. EVENT_CLIPBOARD_PASTE
e.clipboard = value;
  1. EVENT_DROP_FILES
e.filePath = path;
  1. EVENT_GAMEPAD_CONNECTED
e.gamepadId = id;
  1. EVENT_GAMEPAD_DISCONNECTED
e.gamepadId = id;

Previous Tutorial -> Creating a Back Buffer

Next Tutorial -> Basic Animations