Difference between revisions of "Scene Manager"

From GiderosMobile

(added easing)
(added bare bone of a scene class)
(One intermediate revision by the same user not shown)
Line 390: Line 390:
  
 
}
 
}
 +
 +
---- USAGE
 +
--local scenemanager = SceneManager.new(
 +
-- {
 +
-- ["menu"] = Menu,
 +
-- ["level01"] = Level01,
 +
-- }
 +
--)
 +
--
 +
--stage:addChild(scenemanager)
 +
--
 +
----function SceneManager:changeScene(scene, duration, transition, ease)
 +
--scenemanager:changeScene("menu")
 
</source>
 
</source>
 
<br/>
 
<br/>
Line 575: Line 588:
 
easing.inOutSine = function(ratio)
 
easing.inOutSine = function(ratio)
 
return -0.5 * (math.cos(ratio * math.pi) - 1)
 
return -0.5 * (math.cos(ratio * math.pi) - 1)
 +
end
 +
</source>
 +
<br/>
 +
 +
=== <translate>The Bare Bone of a Scene Class</translate> ===
 +
 +
<source lang="lua">
 +
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
 
end
 
</source>
 
</source>
 
<br/>
 
<br/>

Revision as of 01:41, 14 August 2019


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 = gideros.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