Scene Manager

From GiderosMobile

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

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