Scene Manager
From GiderosMobile
Here you will find various resources to help you create games and apps in Gideros Studio.
note:You may have to provide your own assets (fonts, gfx, …).
Scene Manager (with added Transitions)
--[[
SceneManager v1.0.5
changelog:
----------
v1.0.5 - 21.12.2019
Slight change to use new gideros operators
v1.0.4 - 08.04.2012
Added option to filter a list of events during transitions
Moved increment of time to end of onEnterFrame so that time goes from 0 to 1
Added additional "real time" argument to dispatched transitions
Added option to pass user data to a scene when it gets created
v1.0.3 - 19.11.2011
Fixed incorrect calculation of width/height in landscape modes
v1.0.2 - 17.11.2011
Change event names
v1.0.1 - 06.11.2011
Add collectgarbage() to the end of transition
v1.0 - 06.11.2011
Initial release
This code is MIT licensed, see http://www.opensource.org/licenses/mit-license.php
(C) 2010 - 2011 Gideros Mobile
]]
--[[
transitions = {
SceneManager.moveFromRight, -- 1
SceneManager.moveFromLeft, -- 2
SceneManager.moveFromBottom, -- 3
SceneManager.moveFromTop, -- 4
SceneManager.moveFromRightWithFade, -- 5
SceneManager.moveFromLeftWithFade, -- 6
SceneManager.moveFromBottomWithFade, -- 7
SceneManager.moveFromTopWithFade, -- 8
SceneManager.overFromRight, -- 9
SceneManager.overFromLeft, -- 10
SceneManager.overFromBottom, -- 11
SceneManager.overFromTop, -- 12
SceneManager.overFromRightWithFade, -- 13
SceneManager.overFromLeftWithFade, -- 14
SceneManager.overFromBottomWithFade, -- 15
SceneManager.overFromTopWithFade, -- 16
SceneManager.fade, -- 17
SceneManager.crossFade, -- 18
SceneManager.flip, -- 19
SceneManager.flipWithFade, -- 20
SceneManager.flipWithShade, -- 21
}
]]
SceneManager = Core.class(Sprite)
function SceneManager.moveFromRight(scene1, scene2, t)
local width = application:getContentWidth()
scene1:setX(-t * width)
scene2:setX((1 - t) * width)
end
function SceneManager.moveFromLeft(scene1, scene2, t)
local width = application:getContentWidth()
scene1:setX(t * width)
scene2:setX((t - 1) * width)
end
function SceneManager.moveFromBottom(scene1, scene2, t)
local height = application:getContentHeight()
scene1:setY(-t * height)
scene2:setY((1 - t) * height)
end
function SceneManager.moveFromTop(scene1, scene2, t)
local height = application:getContentHeight()
scene1:setY(t * height)
scene2:setY((t - 1) * height)
end
function SceneManager.moveFromRightWithFade(scene1, scene2, t)
local width = application:getContentWidth()
scene1:setAlpha(1 - t)
scene1:setX(-t * width)
scene2:setX((1 - t) * width)
end
function SceneManager.moveFromLeftWithFade(scene1, scene2, t)
local width = application:getContentWidth()
scene1:setAlpha(1 - t)
scene1:setX(t * width)
scene2:setX((t - 1) * width)
end
function SceneManager.moveFromBottomWithFade(scene1, scene2, t)
local height = application:getContentHeight()
scene1:setAlpha(1 - t)
scene1:setY(-t * height)
scene2:setY((1 - t) * height)
end
function SceneManager.moveFromTopWithFade(scene1, scene2, t)
local height = application:getContentHeight()
scene1:setAlpha(1 - t)
scene1:setY(t * height)
scene2:setY((t - 1) * height)
end
function SceneManager.overFromRight(scene1, scene2, t)
local width = application:getContentWidth()
scene2:setX((1 - t) * width)
end
function SceneManager.overFromLeft(scene1, scene2, t)
local width = application:getContentWidth()
scene2:setX((t - 1) * width)
end
function SceneManager.overFromBottom(scene1, scene2, t)
local height = application:getContentHeight()
scene2:setY((1 - t) * height)
end
function SceneManager.overFromTop(scene1, scene2, t)
local height = application:getContentHeight()
scene2:setY((t - 1) * height)
end
function SceneManager.overFromRightWithFade(scene1, scene2, t)
local width = application:getContentWidth()
scene1:setAlpha(1 - t)
scene2:setX((1 - t) * width)
end
function SceneManager.overFromLeftWithFade(scene1, scene2, t)
local width = application:getContentWidth()
scene1:setAlpha(1 - t)
scene2:setX((t - 1) * width)
end
function SceneManager.overFromBottomWithFade(scene1, scene2, t)
local height = application:getContentHeight()
scene1:setAlpha(1 - t)
scene2:setY((1 - t) * height)
end
function SceneManager.overFromTopWithFade(scene1, scene2, t)
local height = application:getContentHeight()
scene1:setAlpha(1 - t)
scene2:setY((t - 1) * height)
end
function SceneManager.fade(scene1, scene2, t)
if t < 0.5 then
scene1:setAlpha((0.5 - t) * 2)
else
scene1:setAlpha(0)
end
if t < 0.5 then
scene2:setAlpha(0)
else
scene2:setAlpha((t - 0.5) * 2)
end
end
function SceneManager.crossFade(scene1, scene2, t)
scene1:setAlpha(1 - t)
scene2:setAlpha(t)
end
function SceneManager.flip(scene1, scene2, t)
local width = application:getContentWidth()
if t < 0.5 then
local s = (0.5 - t) * 2
scene1:setScaleX(s)
scene1:setX((1 - s) * width * 0.5)
else
scene1:setScaleX(0)
scene1:setX(width * 0.5)
end
if t < 0.5 then
scene2:setScaleX(0)
scene2:setX(width * 0.5)
else
local s = (t - 0.5) * 2
scene2:setScaleX(s)
scene2:setX((1 - s) * width * 0.5)
end
end
function SceneManager.flipWithFade(scene1, scene2, t)
local width = application:getContentWidth()
if t < 0.5 then
local s = (0.5 - t) * 2
scene1:setScaleX(s)
scene1:setX((1 - s) * width * 0.5)
scene1:setAlpha(s)
else
scene1:setScaleX(0)
scene1:setX(width * 0.5)
scene1:setAlpha(0)
end
if t < 0.5 then
scene2:setScaleX(0)
scene2:setX(width * 0.5)
scene2:setAlpha(0)
else
local s = (t - 0.5) * 2
scene2:setScaleX(s)
scene2:setX((1 - s) * width * 0.5)
scene2:setAlpha(s)
end
end
function SceneManager.flipWithShade(scene1, scene2, t)
local width = application:getContentWidth()
if t < 0.5 then
local s = (0.5 - t) * 2
scene1:setScaleX(s)
scene1:setX((1 - s) * width * 0.5)
scene1:setColorTransform(1 - t, 1 - t, 1 - t, 1)
else
scene1:setScaleX(0)
scene1:setX(width * 0.5)
scene1:setColorTransform(0.5, 0.5, 0.5, 1)
end
if t < 0.5 then
scene2:setScaleX(0)
scene2:setX(width * 0.5)
scene2:setColorTransform(0.5, 0.5, 0.5, 1)
else
local s = (t - 0.5) * 2
scene2:setScaleX(s)
scene2:setX((1 - s) * width * 0.5)
scene2:setColorTransform(t, t, t, 1)
end
end
local function dispatchEvent(dispatcher, name)
if dispatcher:hasEventListener(name) then
dispatcher:dispatchEvent(Event.new(name))
end
end
local function defaultEase(ratio)
return ratio
end
function SceneManager:init(scenes)
self.scenes = scenes
self.tweening = false
self.transitionEventCatcher = Sprite.new()
self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end
function SceneManager:changeScene(scene, duration, transition, ease, options)
self.eventFilter = options and options.eventFilter
if self.tweening then
return false
end
if self.scene1 == nil then
self.scene1 = self.scenes[scene].new(options and options.userData)
self:addChild(self.scene1)
dispatchEvent(self, "transitionBegin")
dispatchEvent(self.scene1, "enterBegin")
dispatchEvent(self, "transitionEnd")
dispatchEvent(self.scene1, "enterEnd")
return true
end
self.duration = duration
self.transition = transition
self.ease = ease or defaultEase
self.scene2 = self.scenes[scene].new(options and options.userData)
self.scene2:setVisible(false)
self:addChild(self.scene2)
self.time = 0
self.currentTimer = os.timer()
self.tweening = true
return true
end
function SceneManager:filterTransitionEvents(event)
event:stopPropagation()
end
function SceneManager:onTransitionBegin()
if self.eventFilter then
stage:addChild(self.transitionEventCatcher)
for i,event in ipairs(self.eventFilter) do
self.transitionEventCatcher:addEventListener(event, self.filterTransitionEvents, self)
end
end
end
function SceneManager:onTransitionEnd()
if self.eventFilter then
for i,event in ipairs(self.eventFilter) do
self.transitionEventCatcher:removeEventListener(event, self.filterTransitionEvents, self)
end
self.transitionEventCatcher:removeFromParent()
end
end
function SceneManager:onEnterFrame(event)
if not self.tweening then
return
end
if self.time == 0 then
self:onTransitionBegin()
self.scene2:setVisible(true)
dispatchEvent(self, "transitionBegin")
dispatchEvent(self.scene1, "exitBegin")
dispatchEvent(self.scene2, "enterBegin")
end
local timer = os.timer()
local deltaTime = timer - self.currentTimer
self.currentTimer = timer
local t = (self.duration == 0) and 1 or (self.time / self.duration)
if self.transition==nil then
self.transition=SceneManager.fade
end
self.transition(self.scene1, self.scene2, self.ease(t), t)
if self.time == self.duration then
dispatchEvent(self, "transitionEnd")
dispatchEvent(self.scene1, "exitEnd")
dispatchEvent(self.scene2, "enterEnd")
self:onTransitionEnd()
self:removeChild(self.scene1)
self.scene1 = self.scene2
self.scene2 = nil
self.tweening = false
collectgarbage()
end
self.time += deltaTime
if self.time > self.duration then
self.time = self.duration
end
end
--[[
-- USAGE
scenemanager = SceneManager.new(
{
["menu"] = Menu,
["level01"] = Level01,
}
)
stage:addChild(scenemanager)
--function SceneManager:changeScene(scene, duration, transition, ease)
scenemanager:changeScene("menu")
-- you can also pass variables to the new scene, see http://forum.giderosmobile.com/discussion/1474/passing-variables-with-scene-manager
]]
Easing
--[[
Author of this easing functions for Lua is Josh Tynjala
https://github.com/joshtynjala/gtween.lua
Licensed under the MIT license.
Easing functions adapted from Robert Penner's AS3 tweening equations.
*21.12.2019 Modified to use local sin, cos, and pi
*09.12.2018 Modified by @Apollo14: replaced vanilla math functions with faster Gideros ^ operators
]]
--[[
easings = {
easing.inBack, -- 1
easing.outBack, -- 2
easing.inOutBack, -- 3
easing.inBounce, -- 4
easing.outBounce, -- 5
easing.inOutBounce, -- 6
easing.inCircular, -- 7
easing.outCircular, -- 8
easing.inOutCircular, -- 9
easing.inCubic, -- 10
easing.outCubic, -- 11
easing.inOutCubic, -- 12
easing.inElastic, -- 13
easing.outElastic, -- 14
easing.inOutElastic, -- 15
easing.inExponential, -- 16
easing.outExponential, -- 17
easing.inOutExponential, -- 18
easing.linear, -- 19
easing.inQuadratic, -- 20
easing.outQuadratic, -- 21
easing.inOutQuadratic, -- 22
easing.inQuartic, -- 23
easing.outQuartic, -- 24
easing.inOutQuartic, -- 25
easing.inQuintic, -- 26
easing.outQuintic, -- 27
easing.inOutQuintic, -- 28
easing.inSine, -- 29
easing.outSine, -- 30
easing.inOutSine, -- 31
}
]]
local sin,cos=math.sin,math.cos
local pii=3.14159265358979324
local backS = 1.70158
easing = {}
easing.inBack = function(ratio)
return ratio*ratio*((backS+1)*ratio-backS)
end
easing.outBack = function(ratio)
ratio-=1
return ratio*ratio*((backS+1)*ratio+backS)+1
end
easing.inOutBack = function(ratio)
ratio*=2
if ratio < 1 then
return 0.5*(ratio*ratio*((backS*1.525+1)*ratio-backS*1.525))
else
ratio-=2
return 0.5*(ratio*ratio*((backS*1.525+1)*ratio+backS*1.525)+2)
end
end
easing.inBounce = function(ratio)
return 1-easing.outBounce(1-ratio,0,0,0)
end
easing.outBounce = function(ratio)
if ratio < 1/2.75 then
return 7.5625*ratio*ratio
elseif ratio < 2/2.75 then
ratio-=1.5/2.75
return 7.5625*ratio*ratio+0.75
elseif ratio < 2.5/2.75 then
ratio-=2.25/2.75
return 7.5625*ratio*ratio+0.9375
else
ratio-=2.625/2.75
return 7.5625*ratio*ratio+0.984375
end
end
easing.inOutBounce = function(ratio)
ratio*=2
if ratio < 1 then
return 0.5*easing.inBounce(ratio,0,0,0)
else
return 0.5*easing.outBounce(ratio-1,0,0,0)+0.5
end
end
easing.inCircular = function(ratio)
return -((1-ratio*ratio)^0.5-1)
end
easing.outCircular = function(ratio)
return (1-(ratio-1)*(ratio-1))^0.5
end
easing.inOutCircular = function(ratio)
ratio*=2
if ratio < 1 then
return -0.5*((1-ratio*ratio)^0.5-1)
else
ratio-=2
return 0.5*((1-ratio*ratio)^0.5+1)
end
end
easing.inCubic = function(ratio)
return ratio*ratio*ratio
end
easing.outCubic = function(ratio)
ratio-=1
return ratio*ratio*ratio+1
end
easing.inOutCubic = function(ratio)
if ratio < 0.5 then
return 4*ratio*ratio*ratio
else
ratio-=1
return 4*ratio*ratio*ratio+1
end
end
local elasticA = 1
local elasticP = 0.3
local elasticS = elasticP/4
easing.inElastic = function(ratio)
if ratio == 0 or ratio == 1 then
return ratio
end
ratio-=1
return -(elasticA * 2^(10 * ratio) * sin((ratio - elasticS) * (2 * pii) / elasticP))
end
easing.outElastic = function(ratio)
if ratio == 0 or ratio == 1 then
return ratio
end
return elasticA * 2^(-10 * ratio) * sin((ratio - elasticS) * (2 * pii) / elasticP) + 1
end
easing.inOutElastic = function(ratio)
if ratio == 0 or ratio == 1 then
return ratio
end
ratio = ratio*2-1
if ratio < 0 then
return -0.5 * (elasticA * 2^(10 * ratio) * sin((ratio - elasticS*1.5) * (2 * pii) /(elasticP*1.5)))
end
return 0.5 * elasticA * 2^(-10 * ratio) * sin((ratio - elasticS*1.5) * (2 * pii) / (elasticP*1.5)) + 1
end
easing.inExponential = function(ratio)
if ratio == 0 then
return 0
end
return 2^(10 * (ratio - 1))
end
easing.outExponential = function(ratio)
if ratio == 1 then
return 1
end
return 1-2^(-10 * ratio)
end
easing.inOutExponential = function(ratio)
if ratio == 0 or ratio == 1 then
return ratio
end
ratio = ratio*2-1
if 0 > ratio then
return 0.5*2^(10 * ratio)
end
return 1-0.5*2^(-10 * ratio)
end
easing.linear = function(ratio)
return ratio
end
easing.inQuadratic = function(ratio)
return ratio*ratio
end
easing.outQuadratic = function(ratio)
return -ratio*(ratio-2)
end
easing.inOutQuadratic = function(ratio)
if ratio < 0.5 then
return 2*ratio*ratio
end
return -2*ratio*(ratio-2)-1
end
easing.inQuartic = function(ratio)
return ratio*ratio*ratio*ratio
end
easing.outQuartic = function(ratio)
ratio-=1
return 1-ratio*ratio*ratio*ratio
end
easing.inOutQuartic = function(ratio)
if ratio < 0.5 then
return 8*ratio*ratio*ratio*ratio
end
ratio-=1
return -8*ratio*ratio*ratio*ratio+1
end
easing.inQuintic = function(ratio)
return ratio*ratio*ratio*ratio*ratio
end
easing.outQuintic = function(ratio)
ratio-=1
return 1+ratio*ratio*ratio*ratio*ratio
end
easing.inOutQuintic = function(ratio)
if ratio < 0.5 then
return 16*ratio*ratio*ratio*ratio*ratio
end
ratio-=1
return 16*ratio*ratio*ratio*ratio*ratio+1
end
easing.inSine = function(ratio)
return 1-cos(ratio * (pii / 2))
end
easing.outSine = function(ratio)
return sin(ratio * (pii / 2))
end
easing.inOutSine = function(ratio)
return -0.5*(cos(ratio*pii)-1)
end
The Bare Bone of a Scene Class
Level01 = Core.class(Sprite)
function Level01:init()
-- BG
application:setBackgroundColor(0x1234AA)
-- LISTENERS
self:addEventListener("enterBegin", self.onTransitionInBegin, self)
self:addEventListener("enterEnd", self.onTransitionInEnd, self)
self:addEventListener("exitBegin", self.onTransitionOutBegin, self)
self:addEventListener("exitEnd", self.onTransitionOutEnd, self)
end
-- GAME LOOP
function Level01:onEnterFrame(e)
end
-- EVENT LISTENERS
function Level01:onTransitionInBegin()
self:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end
function Level01:onTransitionInEnd()
self:myKeysPressed()
end
function Level01:onTransitionOutBegin()
self:removeEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end
function Level01:onTransitionOutEnd()
end
-- KEYS HANDLER
function Level01:myKeysPressed()
self:addEventListener(Event.KEY_DOWN, function(e)
-- for mobiles and desktops
if e.keyCode == KeyCode.BACK or e.keyCode == KeyCode.ESC then
scenemanager:changeScene("menu", 1, transitions[2], easing.outBack)
end
end)
end