Event system

The Ultimate Guide to Gideros Studio

Event system

Introduction to events

Events are the central mechanism to handle responses and they allow to create interactive applications. All classes that dispatch events inherit from EventDispatcher. The target of an event is a listener function and an optional data value. When an event is dispatched, the registered function is called. If the optional data value is given, it is used as a first parameter while calling the listener function.

In Gideros, events can be divided into two categories:

  • built-in events which are generated by the system (e.g. ENTER_FRAME event, touch events, timer events, etc.)
  • and custom events which can be generated by the user.


According to their event type, built-in events can be broadcasted to multiple targets (e.g. ENTER_FRAME event, touch events, etc.) or can be dispatched to a single target (e.g. timer event).

ENTER_FRAME Event

The Gideros runtime dispatches the built-in Event.ENTER_FRAME event to Sprite instances before rendering the screen. Visual changes made by anyEvent.ENTER_FRAME listener function will be visible at next frame.

This first basic example shows a moving sprite one pixel to the right at each frame. In this example, onEnterFrame function increases the x-coordinate of a sprite object at each frame:

local sprite = Sprite.new()
local function onEnterFrame(event)
   sprite:setX(sprite:getX() + 1)
end
sprite:addEventListener(Event.ENTER_FRAME, onEnterFrame)


The next example shows 3 independent sprites moving one pixel to the right at each frame. In this example, we use the optional data parameter to move independent sprites with one common listener function:

local sprite1 = Sprite.new()
local sprite2 = Sprite.new()
local sprite3 = Sprite.new()
local function onEnterFrame(self, event)
   self:setX(self:getX() + 1)
end
sprite1:addEventListener(Event.ENTER_FRAME, onEnterFrame, sprite1)
sprite2:addEventListener(Event.ENTER_FRAME, onEnterFrame, sprite2)
sprite3:addEventListener(Event.ENTER_FRAME, onEnterFrame, sprite3)


The last example shows subclassing of the Sprite class and registering Event.ENTER_FRAME:

MySprite = gideros.class(Sprite)
function MySprite:init()
   self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end
function MySprite:onEnterFrame(event)
   self:setX(self:getX() + 1)
end


Note: Event.ENTER_FRAME event is dispatched to all Sprite instances no matter these instances are on the scene tree or not. Note: When the ENTER_FRAME event dispatches, the event object contains time and deltaTime. Consider the following example:

local function onEnterFrame(event)
	print(event.time, event.deltaTime)
end
stage:addEventListener(Event.ENTER_FRAME, onEnterFrame)

Mouse and touch events

Gideros runtime dispatches mouse and touch events when the the user’s finger touches the screen. Mouse events are mainly used in single-touch whereas touch events are used in multi-touch applications.

The mouse and touch events are dispatched to Sprite instances which are on the scene tree. If a Sprite instance is not on the scene tree, this instance doesn’t receive mouse and touch events.

Note: Even if touch or mouse doesn’t hit the Sprite instance, the instance receives mouse/touch events.

The order of dispatch is determined by the hierachy of the scene tree. The Sprite instance that is drawn last (top-most sprite) receives the event first. The next sprite at the bottom of the top-most sprite receives the event second and so on. For example, assume that we have an sprite hierachy like this:
Sprite hierarchy.png

which is constructed by the code below:

local A = Sprite.new()
local B = Sprite.new()
local C = Sprite.new()
local D = Sprite.new()
local E = Sprite.new()
local F = Sprite.new()
A:addChild(B)
A:addChild(C)
B:addChild(D)
B:addChild(E)
C:addChild(F)


In this hiearchy, the drawing order is A, B, C, D, E, F while mouse/touch event receive order is F, E, D, C, B, A.

Stopping an event dispatch

It is possible to stop the propagation of mouse and touch events. To stop an event dispatch, invoke the Event:stopPropagation() function on the Eventobject passed to the listener function. In this example below, MOUSE_DOWN event is dispatched only to F, E, D and C:

local A = Sprite.new()
local B = Sprite.new()
local C = Sprite.new()
local D = Sprite.new()
local E = Sprite.new()
local F = Sprite.new()
-- stop propagation at sprite C
C:addEventListener(Event.MOUSE_DOWN, function(event)
	event:stopPropagation()
end)
A:addChild(B)
A:addChild©
B:addChild(D)
B:addChild(E)
C:addChild(F)


Note: stopPropagation is only for mouse and touch events. Because only for them there is a definite dispatching order (the display object on top receives the event first).

Timer events

The Timer class is used for executing code at specified time intervals. Each Timer object dispatches Event.TIMER event at specified frequency. The steps to use Timer class are as follows:

1- Create a new Timer object with specified frequency and specified total number of Event.TIMER events to be triggered. For example, the following code sets the frequency to 1000 miliseconds and sets the count to 5:

local timer = Timer.new(1000, 5)


2- Register to the Event.TIMER event with a listener function:

local function onTimer(event)
-- will be executed 5 times at 1000 milliseconds intervals
end
timer:addEventListener(Event.TIMER, onTimer)


3- Start the timer.

timer:start()


4- To stop the timer, you can use Timer:stop() function:

timer:stop()


Event.TIMER_COMPLETE event is triggered after finishing the specified number of timer events.

local function onTimerComplete(event)
-- will be executed after the specified 
-- number of timer events (5) are dispatched
end
timer:addEventListener(Event.TIMER_COMPLETE, onTimerComplete)


Also, it is possible to pause and resume all the timers in your application. It is very useful when you are implementing a pause/resume functionality in your game:

-- pause all timers. 
-- if all timers are alredy paused, does nothing.
Timer.pauseAllTimers()      
-- resume all timers. if all timers 
-- are alredy running, does nothing.
Timer.resumeAllTimers()

ADDED_TO_STAGE and REMOVED_FROM_STAGE Events

If a sprite is added to the scene tree, the sprite instance and all of it’s descendants receive Event.ADDED_TO_STAGE event. Similarly, if a sprite is removed from the scene tree, the sprite instance and all of it’s descendants receive Event.REMOVED_FROM_STAGE event. These events are used to detect when a Sprite instance is added to, or removed from, the scene tree. For example, by the help of these events, it is possible to register Event.ENTER_FRAME event only for the sprites that are on the scene tree:

MySprite = gideros.class(Sprite)
function MySprite:init()
	self:addEventListener(Event.ADDED_TO_STAGE, self.onAddedToStage, self)
	self:addEventListener(Event.REMOVED_FROM_STAGE, self.onRemovedFromStage, self)
end
function MySprite:onAddedToStage(event)
	self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end
function MySprite:onRemovedFromStage(event)
	self:removeEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end
function MySprite:onEnterFrame(event)
	-- enter frame logic
end

Custom events

To dispatch a new custom user defined event, create the event with Event.new() function and dispatch it with EventDispatcher:dispatchEvent(). Example:

ClassA = gideros.class(EventDispatcher)
ClassB = gideros.class(EventDispatcher)
function ClassA:funcA(event)
   print("funcA", self, event:getType(), event:getTarget())
end
local a = ClassA.new()
local b = ClassB.new()
b:addEventListener("myevent", a.funcA, a)
-- when b dispatches an "myevent" event,
-- a.funcA will be called with 'a'as first parameter
b:dispatchEvent(Event.new("myevent"))
-- will print "funcA"

List of all built-in events

The following tables show a list of all built-in events in Gideros SDK, with a brief explanation of what they are for.

Frame & stage events

ENTER_FRAME Dispatched to all Sprite instances before rendering the screen.
   • event.frameCount: The total number of frames that have passed since the start of the application
   • event.time: Time in seconds since the start of the application
   • event.deltaTime: The time in seconds between the last frame and the current frame
ADDED_TO_STAGE Dispatched when target Sprite instance is added to the stage.
REMOVED_FROM_STAGE Dispatched when target Sprite instance is removed from the stage.

Mouse events

MOUSE_DOWN Dispatched to all Sprite instances on the scene tree when user presses the mouse button or starts the first touch.
   • event.x: The x-coordinate of the mouse or touch
   • event.y: The y-coordinate of the mouse or touch
MOUSE_MOVE Dispatched to all Sprite instances on the scene tree when user moves the mouse or moves the first touch.
   • event.x: The x-coordinate of the mouse or touch
   • event.y: The y-coordinate of the mouse or touch
MOUSE_UP Dispatched to all Sprite instances on the scene tree when user releases the mouse button or ends the first touch.
   • event.x: The x-coordinate of the mouse or touch
   • event.y: The y-coordinate of the mouse or touch

Touch events

TOUCHES_BEGIN Dispatched to all Sprite instances on the scene tree when one or more fingers touch down.
   • event.touches: Array of current touches where each element contains x, y and id
   • event.allTouches: Array of all touches where each element contains x, y and id
TOUCHES_MOVE Dispatched to all Sprite instances on the scene tree when one or more fingers move.
   • event.touches: Array of current touches where each element contains x, y and id
   • event.allTouches: Array of all touches where each element contains x, y and id
TOUCHES_END Dispatched to all Sprite instances on the scene tree when one or more fingers are raised.
   • event.touches: Array of current touches where each element contains x, y and id
   • event.allTouches: Array of all touches where each element contains x, y and id
TOUCHES_CANCEL Dispatched to all Sprite instances on the scene tree when a system event (such as a low-memory warning) cancels a touch event.
   • event.touches: Array of current touches where each element contains x, y and id
   • event.allTouches: Array of all touches where each element contains x, y and id

Application events

APPLICATION_START Dispatched to all event listeners (broadcast event) right after the application is launched and all Lua codes are executed.
APPLICATION_EXIT Dispatched to all event listeners (broadcast event) when the application is about to exit. If an application is forced to be terminated (e.g. by double tapping the home button and kill the application), this event may not be dispatched. If you want to save your game state before exiting, save your state also on APPLICATION_SUSPEND event.
APPLICATION_SUSPEND Dispatched to all event listeners (broadcast event) when the application goes to background. When an application goes to background, ENTER_FRAME and TIMER events are not dispatched until the application is resumed from background.
APPLICATION_RESUME Dispatched to all event listeners (broadcast event) when the application is resumed from background.

Sound & Timer events

SOUND_COMPLETE Dispatched when a sound has finished playing.
TIMER Dispatched whenever a Timer object reaches an interval specified according to the delay property.
TIMER_COMPLETE Dispatched whenever a Timer object has completed the number of requests specified according to the repeatCount property.

UrlLoader events

COMPLETE Dispatched after all data is received and placed in the data property of the UrlLoader object.
ERROR Dispatched when UrlLoader fails and terminates the download.
PROGRESS Dispatched by UrlLoader as the notification of how far the download has progressed.
   • event.bytesLoaded: The number of bytes loaded
   • event.bytesTotal: The total number of bytes that will be loaded

Physics events

BEGIN_CONTACT Dispatched by b2.World when two fixtures begin to overlap. This is dispatched for sensors and non-sensors. This event can only occur inside the time step.
   • event.fixtureA: The first fixture in this contact
   • event.fixtureB: The second fixture in this contact
END_CONTACT Dispatched by b2.World when two fixtures cease to overlap. This is dispatched for sensors and non-sensors. This may be dispatched when a body is destroyed, so this event can occur outside the time step.
   • event.fixtureA: The first fixture in this contact
   • event.fixtureB: The second fixture in this contact
PRE_SOLVE Dispatched by b2.World after collision detection, but before collision resolution.
   • event.fixtureA: The first fixture in this contact
   • event.fixtureB: The second fixture in this contact
POST_SOLVE Dispatched by b2.World after collision resolution.
   • event.fixtureA: The first fixture in this contact
   • event.fixtureB: The second fixture in this contact