Scene Manager

This page contains changes which are not marked for translation.

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.3
changelog:
----------
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 
]]

SceneManager = Core.class(Sprite)

local function getContentWidth()
	local orientation = stage:getOrientation()
	if orientation == Stage.LANDSCAPE_LEFT or orientation == Stage.LANDSCAPE_RIGHT then
		return application:getLogicalHeight()
	else
		return application:getLogicalWidth()
	end
end

local function getContentHeight()
	local orientation = stage:getOrientation()
	if orientation == Stage.LANDSCAPE_LEFT or orientation == Stage.LANDSCAPE_RIGHT then
		return application:getLogicalWidth()
	else
		return application:getLogicalHeight()
	end
end

function SceneManager.moveFromRight(scene1, scene2, t)
	local width = getContentWidth()
	scene1:setX(-t * width)
	scene2:setX((1 - t) * width)
end

function SceneManager.moveFromLeft(scene1, scene2, t)
	local width = getContentWidth()
	scene1:setX(t * width)
	scene2:setX((t - 1) * width)
end

function SceneManager.overFromRight(scene1, scene2, t)
	local width = getContentWidth()
	scene2:setX((1 - t) * width)
end

function SceneManager.overFromLeft(scene1, scene2, t)
	local width = getContentWidth()
	scene2:setX((t - 1) * width)
end

function SceneManager.moveFromRightWithFade(scene1, scene2, t)
	local width = getContentWidth()
	scene1:setAlpha(1 - t)
	scene1:setX(-t * width)
	scene2:setX((1 - t) * width)
end

function SceneManager.moveFromLeftWithFade(scene1, scene2, t)
	local width = getContentWidth()
	scene1:setAlpha(1 - t)
	scene1:setX(t * width)
	scene2:setX((t - 1) * width)
end

function SceneManager.overFromRightWithFade(scene1, scene2, t)
	local width = getContentWidth()
	scene1:setAlpha(1 - t)
	scene2:setX((1 - t) * width)
end

function SceneManager.overFromLeftWithFade(scene1, scene2, t)
	local width = getContentWidth()
	scene1:setAlpha(1 - t)
	scene2:setX((t - 1) * width)
end

function SceneManager.moveFromBottom(scene1, scene2, t)
	local height = getContentHeight()
	scene1:setY(-t * height)
	scene2:setY((1 - t) * height)
end

function SceneManager.moveFromTop(scene1, scene2, t)
	local height = getContentHeight()
	scene1:setY(t * height)
	scene2:setY((t - 1) * height)
end

function SceneManager.overFromBottom(scene1, scene2, t)
	local height = getContentHeight()
	scene2:setY((1 - t) * height)
end

function SceneManager.overFromTop(scene1, scene2, t)
	local height = getContentHeight()
	scene2:setY((t - 1) * height)
end

function SceneManager.moveFromBottomWithFade(scene1, scene2, t)
	local height = getContentHeight()
	scene1:setAlpha(1 - t)
	scene1:setY(-t * height)
	scene2:setY((1 - t) * height)
end

function SceneManager.moveFromTopWithFade(scene1, scene2, t)
	local height = getContentHeight()
	scene1:setAlpha(1 - t)
	scene1:setY(t * height)
	scene2:setY((t - 1) * height)
end

function SceneManager.overFromBottomWithFade(scene1, scene2, t)
	local height = getContentHeight()
	scene1:setAlpha(1 - t)
	scene2:setY((1 - t) * height)
end

function SceneManager.overFromTopWithFade(scene1, scene2, t)
	local height = 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 = 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 = 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 = 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:addEventListener(Event.ENTER_FRAME, self.onEnterFrame, self)
end

function SceneManager:changeScene(scene, duration, transition, ease)
	if self.tweening then
		return
	end

	if self.scene1 == nil then
		self.scene1 = self.scenes[scene].new()
		self:addChild(self.scene1)
		dispatchEvent(self, "transitionBegin")
		dispatchEvent(self.scene1, "enterBegin")
		dispatchEvent(self, "transitionEnd")
		dispatchEvent(self.scene1, "enterEnd")
		return
	end

	self.duration = duration
	self.transition = transition
	self.ease = ease or defaultEase

	self.scene2 = self.scenes[scene].new()
	self.scene2:setVisible(false)
	self:addChild(self.scene2)

	self.time = 0
	self.currentTimer = os.timer()
	self.tweening = true
end

function SceneManager:onEnterFrame(event)
	if not self.tweening then
		return
	end

	if self.time == 0 then
		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

	self.time = self.time + deltaTime

	if self.time > self.duration then
		self.time = self.duration
	end

	local t = (self.duration == 0) and 1 or (self.time / self.duration)

	self.transition(self.scene1, self.scene2, self.ease(t))

	if self.time == self.duration then
		dispatchEvent(self, "transitionEnd")
		dispatchEvent(self.scene1, "exitEnd")
		dispatchEvent(self.scene2, "enterEnd")

		self:removeChild(self.scene1)
		self.scene1 = self.scene2
		self.scene2 = nil
		self.tweening = false

		collectgarbage()
	end
end

-- TRANSITIONS
transitions = {
	SceneManager.moveFromLeft,
	SceneManager.moveFromRight,
	SceneManager.moveFromBottom,
	SceneManager.moveFromTop,
	SceneManager.moveFromLeftWithFade,
	SceneManager.moveFromRightWithFade,
	SceneManager.moveFromBottomWithFade,
	SceneManager.moveFromTopWithFade,
	SceneManager.overFromLeft,
	SceneManager.overFromRight,
	SceneManager.overFromBottom,
	SceneManager.overFromTop,
	SceneManager.overFromLeftWithFade,
	SceneManager.overFromRightWithFade,
	SceneManager.overFromBottomWithFade,
	SceneManager.overFromTopWithFade,
	SceneManager.fade,
	SceneManager.crossFade,
	SceneManager.flip,
	SceneManager.flipWithFade,
	SceneManager.flipWithShade,
}

---- USAGE
--local scenemanager = SceneManager.new(
--	{
--		["menu"] = Menu,
--		["level01"] = Level01,
--	}
--)
--
--stage:addChild(scenemanager)
--
----function SceneManager:changeScene(scene, duration, transition, ease)
--scenemanager:changeScene("menu")

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.
]]

local backS = 1.70158
easing = {}
easing.inBack = function(ratio)
	return ratio *ratio * ((backS + 1) * ratio - backS)
end
easing.outBack = function(ratio)
	ratio = ratio - 1
	return ratio * ratio * ((backS + 1) * ratio + backS) + 1
end
easing.inOutBack = function(ratio)
	ratio = ratio * 2
	if ratio < 1 then
		return 0.5 * (ratio * ratio * ((backS * 1.525 + 1) * ratio - backS * 1.525))
	else 
		ratio = 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 = ratio - 1.5 / 2.75
		return 7.5625 * ratio * ratio + 0.75
	elseif ratio < 2.5 / 2.75 then
		ratio = ratio - 2.25 / 2.75
		return 7.5625 * ratio * ratio + 0.9375
	else
		ratio = ratio - 2.625 / 2.75
		return 7.5625 * ratio * ratio + 0.984375
	end
end
easing.inOutBounce = function(ratio)
	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 -(math.sqrt(1 - ratio * ratio) - 1)
end
easing.outCircular = function(ratio)
	return math.sqrt(1 - (ratio - 1) * (ratio - 1))
end
easing.inOutCircular = function(ratio)
	ratio = ratio * 2
	if ratio < 1 then
		return -0.5 * (math.sqrt(1 - ratio * ratio) - 1)
	else
		ratio = ratio - 2
		return 0.5 * (math.sqrt(1 - ratio * ratio) + 1)
	end
end
easing.inCubic = function(ratio)
	return ratio * ratio * ratio
end
easing.outCubic = function(ratio)
	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 = 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 = ratio - 1
	return -(elasticA * math.pow(2, 10 * ratio) * math.sin((ratio - elasticS) * (2 * math.pi) / elasticP))
end
easing.outElastic = function(ratio)
	if ratio == 0 or ratio == 1 then
		return ratio
	end
	return elasticA * math.pow(2, -10 * ratio) * math.sin((ratio - elasticS) * (2 * math.pi) / 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 * math.pow(2, 10 * ratio) * math.sin((ratio - elasticS * 1.5) * (2 * math.pi) /(elasticP * 1.5)))
	end
	return 0.5 * elasticA * math.pow(2, -10 * ratio) * math.sin((ratio - elasticS * 1.5) * (2 * math.pi) / (elasticP * 1.5)) + 1
end
easing.inExponential = function(ratio)
	if ratio == 0 then
		return 0
	end
	return math.pow(2, 10 * (ratio - 1))
end
easing.outExponential = function(ratio)
	if ratio == 1 then
		return 1
	end
	return 1 - math.pow(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 * math.pow(2, 10 * ratio)
	end
	return 1 - 0.5 * math.pow(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 = 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 = 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 = 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 = ratio - 1
	return 16 * ratio * ratio * ratio * ratio * ratio + 1
end
easing.inSine = function(ratio)
	return 1 - math.cos(ratio * (math.pi / 2))
end
easing.outSine = function(ratio)
	return math.sin(ratio * (math.pi / 2))
end
easing.inOutSine = function(ratio)
	return -0.5 * (math.cos(ratio * math.pi) - 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