CoronaSDK场景管理库:Composer library (上)

Composer是corona官方提供的场景创建和管理系统,我大CoronaSDK果然威武!

1 场景者,何也

corona中的每个场景是以一个lua文件的形式出现,多个.lua文件分散在你的项目中组成众多场景。你编写这些lua文件的时候必须遵循一些规则,以便Composer可以正确理解你的场景代码。

场景代码文件中须得包含两样东西,以使得场景可以被正确地初始化:

  • 四个监听函数来处理Composer生成的场景事件
  • 四行监听函数声明以及把场景对象返回的语句

具体的例子呆会可以看后面的场景模版。

因为场景都是Lua模块,所以加载的方式首先是require()来加载到内存中,并且只能加载一次。有一件事非常重要,就是放在四个场景监听函数之外的代码,在每次场景显示和隐藏时,并不会被重复执行。

场景对象的创建,主要是通过调用compose.newScene()。这个对象保存着Composer必须访问的重要的场景数据,对于开发者来说,最重要的方面,就是场景的视图(self.view)--这是一个display group对象,场景中所有可视的内容都被添加于其中。例如像image、vector对象这些display object都必须加入这个视图(view),连同交互对象如widgets也都如此。这是关于Composer最重要的概念。

一个场景的self.view这个组对象,位于显示层级的底部。如果你创建一个display object而不加入场景的view组,他们将会处于Composer舞台的前面。

2 生命周期

Composer生命周期起于main.lua。然而main.lua自己并不是一个Composer场景--这只不过是一个初始化代码,然后它会通过composer.gotoscene()来启动第一个场景。在这次调用中,需要指定被加载的场景(也是文件)的名字,去掉.lua扩展名:

local composer = require( "composer" )

-- Code to initialize your app

-- Assumes that "scene1.lua" exists and is configured as a Composer scene
composer.gotoScene( "scene1" )

一旦加载,场景的生命周期就开始了,它也将遵循下面基本规则:

  • 场景文件被加载,并且一个Composer场景对象被创建。
  • 场景视图被创建(如果它并不是已经存在的话),并会分发一个创建事件给场景本地的scene:create()函数。
  • 如果一个场景已经存在于屏幕上,它会被隐藏、或者视情况回收或删除。
  • 新的场景显示出来。

3 场景事件

四个不同的生命周期函数,来处理Composer产生的事件。

  • scene:create()
  • scene:show()
  • scene:hide()
  • scene:destory()

scene:create()

当一个场景刚被加载时,还没有一个关联的self.view产生,Composer将会分发一个事件给本地函数scene:create()。如果self.view已经存在,则create事件就会跳过。因为,默认情况下,Composer试图把self.view保持在内存里,假设你在某个时候还会返回这个场景。这样,scene:create()函数将不会在每次场景被显示时都被执行。

local composer = require( "composer" )

local scene = composer.newScene()

function scene:create( event )

    local sceneGroup = self.view

    -- Initialize the scene here.
    -- Example: add display objects to "sceneGroup", add touch listeners, etc.
end

scene:addEventListener( "create", scene )

return scene

这个scene:create函数对于下面这些事来说是一个恰好的时机:

  • 创建用户界面对象
  • 创建其他场景需要的显示对象,包括按钮、文字和图像

不过这并不包括native对象,比如文本输入框--这些应该在scene:show()函数里创建。

重要提示:

如果display object应该成为场景的一部分并被Composer所管理--例如当场景被删除时就清除--这些对象就必须被插入到场景的self.view里。注意下面self.view被简单赋给本地变量sceneGroup引用。

local composer = require( "composer" )

local scene = composer.newScene()

function scene:create( event )
    local sceneGroup = self.view

    local background = display.newRect( display.contentCenterX, display.contentCenterY, display.contentWidth, display.contentHeight )
    background:setFillColor( 1, 0, 0.2 )

    sceneGroup:insert( background )
end

scene:addEventListener( "create", scene )

return scene

一旦创建完成,场景的视图便被隐藏。根据你的scene transition设置,它将处于当前存在的场景之下或甚至屏幕之外。因为这个场景还不可见的,你这时不应该开始任何timer或激活任何物理对象。同样如果你会用到场景特定的音效,你可以将它加载到内存里,而不是现在就播放它。

scene:show()

这个函数将会在场景每次被显示时被激活两次:一次是在场景正要显示出来之前,另一次在场景完全显示到屏幕上之后。

local composer = require( "composer" )

local scene = composer.newScene()

function scene:show( event )

    local sceneGroup = self.view
    local phase = event.phase

    if ( phase == "will" ) then
        -- Called when the scene is still off screen (but is about to come on screen).
    elseif ( phase == "did" ) then
        -- Called when the scene is now on screen.
        -- Insert code here to make the scene come alive.
        -- Example: start timers, begin animation, play audio, etc.
    end
end

scene:addEventListener( "show", scene )

return scene

正如你所看到,这个传给scene:show()的参数event,包含了一个phase字段--它可以取两个值:“will”或"did"。

  • will:发生在场景来到屏幕上之前。这是重新摆放对象的好机会,因为场景前一次显示之后有可能这些对象的位置等属性都发生了改变。(比如重新开始一个关卡)。
  • did:发生在场景完全处于屏幕上之后。这是一个开启transition或timer,播放场景音乐(scene:create()时被加载的)的好机会,如果你用到了物理引擎,这时候也适合开启物理模拟器。

scene:hide()

这个函数在每次场景被隐藏时被激活两次:一次在场景正要离开屏幕时,另一次在场景已经完全离开屏幕后。

local composer = require( "composer" )

local scene = composer.newScene()

function scene:hide( event )

    local sceneGroup = self.view
    local phase = event.phase

    if ( event.phase == "will" ) then
        -- Called when the scene is on screen (but is about to go off screen).
        -- Insert code here to "pause" the scene.
        -- Example: stop timers, stop animation, stop audio, etc.
    elseif ( phase == "did" ) then
        -- Called immediately after scene goes off screen.
    end
end

scene:addEventListener( "hide", scene )

return scene

类似于show,传给scene:hide()的参数event,也有一个phase字段,分别可以取值:"will"或"did":

will:发生在当场景正要离开屏幕的时候。这是暂停或停止物理系统‘取消timer和transition、停止场景音乐的好机会。

did:这个阶段不需要太多的动作,尽管你可以在这里删除场景self.view或者甚至删除场景。

scene:destrory()

这个函数就是Composer用来清除场景中的display object(任何你插入self.view组的对象)。scene:destroy()在场景被清除前被调用。在这里,你可以undo你在scene:create()里所做的事---没有被关联到场景display object上的东西。例如,dispose()场景音乐等。

function scene:destroy( event )

    local sceneGroup = self.view

    -- Called prior to the removal of scene‘s view ("sceneGroup").
    -- Insert code here to clean up the scene.
end

因为Composer出于性能考虑,视图保持场景在内存中,这个函数指挥在下面这些情况被调用:

  • 显式调用composer.removeScene()
  • Composer被设置为自动删除场景的视图
  • app收到操作系统发出的低内存警告

如果你在scene:create()函数里加载音乐文件到内存里,scene:destroy()就是dispose这个音乐的好时机。同理,如果你在scene:create()里建立了数据库连接,那么在这里你可以关闭这个连接。

4 场景模版

下面这个模版就是你创建新场景文件时可以使用的。注意模版中包含的监听事件函数是场景中所有可能的事件,但是你可以只加入你想要处理的。

local composer = require( "composer" )

local scene = composer.newScene()

-- -----------------------------------------------------------------------------------------------------------------
-- All code outside of the listener functions will only be executed ONCE unless "composer.removeScene()" is called.
-- -----------------------------------------------------------------------------------------------------------------

-- local forward references should go here

-- -------------------------------------------------------------------------------

-- "scene:create()"
function scene:create( event )

    local sceneGroup = self.view

    -- Initialize the scene here.
    -- Example: add display objects to "sceneGroup", add touch listeners, etc.
end

-- "scene:show()"
function scene:show( event )

    local sceneGroup = self.view
    local phase = event.phase

    if ( phase == "will" ) then
        -- Called when the scene is still off screen (but is about to come on screen).
    elseif ( phase == "did" ) then
        -- Called when the scene is now on screen.
        -- Insert code here to make the scene come alive.
        -- Example: start timers, begin animation, play audio, etc.
    end
end

-- "scene:hide()"
function scene:hide( event )

    local sceneGroup = self.view
    local phase = event.phase

    if ( phase == "will" ) then
        -- Called when the scene is on screen (but is about to go off screen).
        -- Insert code here to "pause" the scene.
        -- Example: stop timers, stop animation, stop audio, etc.
    elseif ( phase == "did" ) then
        -- Called immediately after scene goes off screen.
    end
end

-- "scene:destroy()"
function scene:destroy( event )

    local sceneGroup = self.view

    -- Called prior to the removal of scene‘s view ("sceneGroup").
    -- Insert code here to clean up the scene.
    -- Example: remove display objects, save state, etc.
end

-- -------------------------------------------------------------------------------

-- Listener setup
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )

-- -------------------------------------------------------------------------------

return scene

5 跳转场景

一旦你创建了场景文件,你需要一个方法去访问他们。在Composer中,就是通过composer.gotoScene(sceneName)来完成。这个sceneName参数,对应着lua文件的名字,只是不带.lua扩展名而已。例如,如果你有一个名为menu.lua的场景文件,你访问这个场景的方式就是:

composer.gotoScene( "menu" )

另外,有一些参数,你也可以传给composer.gotoScene()来控制转场动画,或传递数据给这个场景。你可以做如下事:

  • 设置转场特效
  • 设置转场时间
  • 传一个table作为场景的参数数据
local options = {
    effect = "fade",
    time = 500,
    params = {
        someKey = "someValue",
        someOtherKey = 10
    }
}
composer.gotoScene( "menu", options )

而在场景中,读取这个参数params则如下:

function scene:create( event )
    local sceneGroup = self.view
    local params = event.params

    print( params.someKey )
    print( params.someOtherKey )
end

重要提示:

因为Composer默认把当前场景视图保存在内存里,所以scene:create()函数只有在场景第一次被创建时被调用。这样,如果你传一个table作为参数给scene:create(),它也只能在第一次被创建时有效。

6 转场特效

  • "fade"
  • "crossFade"
  • "zoomOutIn"
  • "zoomOutInFade"
  • "zoomInOut"
  • "zoomInOutFade"
  • "flip"
  • "flipFadeOutIn"
  • "zoomOutInRotate"
  • "zoomOutInFadeRotate"
  • "zoomInOutRotate"
  • "zoomInOutFadeRotate"
  • "fromRight" — over current scene
  • "fromLeft" — over current scene
  • "fromTop" — over current scene
  • "fromBottom" — over current scene
  • "slideLeft" — pushes current scene off
  • "slideRight" — pushes current scene off
  • "slideDown" — pushes current scene off
  • "slideUp" — pushes current scene off

7 场景管理

Composer的一个重要特性就是,大部分时候它会自动管理display object,当然前提是你把它们插入到场景的view组里:

function scene:create( event )

    local sceneGroup = self.view

    local menuBack = display.newRect( display.contentCenterX, display.contentCenterY, 280, 360 )
    sceneGroup:insert( menuBack )
end

一旦这个场景被回收或删除,Composer将会恰当地清理menuBack对象,连同其他被插入view组的对象。被应用到这些对象上的touch、tap、collision一类监听器也将会删除。

重要提示:

正如删除Composer管理之外的display object一样,你还应该在结束一个场景时对下面这些东西负责:

  • 删除Runtime listener
  • 取消transition和timers
  • dispose你所加载的音频
  • 删掉和赋nil引用给native对象
  • 关闭任何你打开的文件,包括数据库

8 自动回收场景

默认情况下,当改变场景时,composer保持当前场景在内存中。假如你频繁切换场景的话,这样的确可以提升性能。如果你希望当前场景改变到一个新的场景时就回收当前场景,你可以设置composer.recycleOnSceneChange属性为true:

composer.recycleOnSceneChange = true

恢复到默认行为,让view可以在切换时被保存,则可以设置属性为false:

composer.recycleOnSceneChange = false

很重要的一点是,这两种情况都不会把场景从lua内存中卸载。为了显式从内存中删除场景,就需要使用composer.removeScene()。

9 删除场景

如果你彻底用完了一个场景,并再也不打算访问它了,你可以通过下面的API删除之:

composer.removeScene( sceneName [, shouldRecycle])

例如,如果你想删除menu.lua中的view组以及场景对象,那么调用:

composer.removeScene( "menu" )

也可以传入一个参数,把shouldRecycle设置为true。这样将会从显示层次中删除场景的view,而它仍然会保存在lua内存中:

composer.removeScene( "menu", true )

10 重新加载场景

重新加载场景需要一些不同的方式。许多人想在scene:create()函数里创建和定位所有的场景显示对象。然而如果你重新加载场景,这个函数不会再次被调用,因为场景的view已经存在了。已经移动过的对象(比如游戏中的橘色)在你重新加载的时候依然保持原位,监听函数之外定义的变量也将保持他们当前的值。例如,如果你在监听函数之外设置一个分数变量,他在你重新加载场景的时候不会重置到那个初值。

甚至如果你销毁了场景的view,那些变量也还是不会重置。就算scence:create()可以重新执行,但是监听函数以外的代码也无法重新执行。

重新加载场景最好的办法,就是使用一个中间场景。在游戏中,这是经常被用来做一个“过场动画”,也可能显示玩家表现的一个评价,再或者一个菜单选项例如“重玩”和“退出”等等。使用一个中间过度场景,你可以手动删除你想要重新加载的场景,导致你再次加载它的时候有一个新的开始。然而你仍然需要在scene:show()函数的will阶段重新设置变量和重新放置对象。

如果你想跳过过度场景方法,你可以通过调用自己的方法来重新加载一个场景:

local currScene = composer.getSceneName( "current" )
composer.gotoScene( currScene )
时间: 2024-10-19 02:21:09

CoronaSDK场景管理库:Composer library (上)的相关文章

CoronaSDK场景管理库:Composer library (下)

1 覆层场景 composer允许你拥有一个覆层场景.(在任何时刻,只能有一个覆层场景被显示)这是一种特殊的场景,可以加载之后覆盖在活动场景(父场景)之上.一个覆层场景的结构,和其他composer场景并无二致. 1.1 显示一个覆层场景 为了显示一个覆层场景,需要调用函数composer.showOverlay().因为一个覆层场景一般不会覆盖住整个场景,用户可能随时和底下的父场景发生交互.如果你想阻止用户和父场景交互的话,那么可以把option中的isModal参数设置为true.这样做就可

Php学习之依赖管理工具composer详解

本文和大家分享的主要是php中依赖管理工具composer相关用法,一起来看看吧,希望对大家学习php有所帮助. 什么是依赖管理工具 当你引用某个第三方库时,如果这个库使用到了另外一个或若干个第三方库,再或许另外一个第三方库又有其他的依赖,这样的话手动维护你需要下载安装N个包.用来解决由此产生的问题的工具就叫做依赖管理工具. 有哪些常见的依赖管理工具 Java的maven.gradle,NodeJs的npm,IOS的CocoaPods,PHP的composer 大部分编程语言都会有自己的常用依赖

有用PHP依赖管理工具Composer新手教程

PHP依赖管理工具Composer新手教程 Composer 是 PHP 的一个依赖管理工具.它同意你申明项目所依赖的代码库,它会在你的项目中为你安装他们. 依赖管理 Composer 不是一个包管理器. 是的,它涉及 "packages" 和 "libraries",但它在每一个项目的基础上进行管理,在你项目的某个文件夹中(比如 vendor)进行安装. 默认情况下它不会在全局安装不论什么东西.因此,这不过一个依赖管理. 这样的想法并不新奇,Composer 受到

php管理工具composer安装&测试

我把它放在系统的PATH目录中,这样就能在全局访问它. curl -sS https://getcomposer.org/installer | php mv composer.phar /usr/local/bin/composer 此命令只检查少量的PHP配置,然后下载 composer.phar 文件到你的工作目录,此文件就是Composer执行文件,它是一个PHAR(PHP归档文件,里面可以包含任何文件,并且可以在PHP命令行执行). 测试是否安装成功 composer -V Compo

实用PHP依赖管理工具Composer入门教程

PHP依赖管理工具Composer入门教程 Composer 是 PHP 的一个依赖管理工具.它允许你申明项目所依赖的代码库,它会在你的项目中为你安装他们. 依赖管理 Composer 不是一个包管理器.是的,它涉及 "packages" 和 "libraries",但它在每个项目的基础上进行管理,在你项目的某个目录中(例如 vendor)进行安装.默认情况下它不会在全局安装任何东西.因此,这仅仅是一个依赖管理. 这种想法并不新鲜,Composer 受到了 node

分享一个嵌入式httpdserver开发库 - boahttpd library

http://sourceforge.net/projects/boahttpd/ 一个C接口的开发库,适用于 windows/linux/或其它嵌入式平台,支持CGI扩展,支持多线程.採用面向对象开发,一个应用里能够同一时候开多个http server,仅仅要port不同就互不影响.主要应用场景应该是嵌入式应用(所谓boa-server的概念),在须要做一个基本web的设备管理使用.在样例中就是展示,从页面信息的提交.到处理.到结果的返回,里面结合jquery/bootstrap网页技术,能够

HTML5 离线缓存管理库

一.HTML5离线缓存技术 支持离线缓存是HTML5中的一个重点,离线缓存就是让用户即使在断网的情况下依然可以正常的运行应用.传统的本地存储数据的方式有 localstorage,sessionstorage和cookie.但是这些传统的方式有着致命的弊端.首先这些传统的存储方式的最大使用空间有 限,最多不超过5M;其次它们处理大规模的结构化数据的能力有限.鉴于传统方式的局限性,HTML5提出了三种新的离线缓存解决方案:Web SQL,indexedDB和File System. 其中Web S

在数据库访问项目中使用微软企业库Enterprise Library,实现多种数据库的支持

在我们开发很多项目中,数据访问都是必不可少的,有的需要访问Oracle.SQLServer.Mysql这些常规的数据库,也有可能访问SQLite.Access,或者一些我们可能不常用的PostgreSQL.IBM DB2.或者国产达梦数据库等等,这些数据库的共同特点是关系型数据库,基本上开发的模型都差不多,不过如果我们基于ADO.NET的基础上进行开发的话,那么各种数据库都有自己不同的数据库操作对象,微软企业库Enterprise Library是基于这些不同数据库的操作做的抽象模型,适合多数据

转:Ogre的八叉树场景管理器OctreeSceneManager

上面是我绘制的一张图. 关于八叉树场景管理器主要需要关注两个类,其一是松散八叉树的数据结构Ogre::Octree,其二是八叉树场景管理器Ogre::OctreeSceneManager. 下面摘录图片中的文字: 松散八叉树的数据结构. 属性:其中mBox为其包围盒,mHalfSize定义为包围盒大小的一半.mChildren是一个大小为8的静态数组,里面保存了8个Octree指针,由八叉树场景管理器创建,由本类管理.mNodes为挂接到当前八叉树上面的八叉树场景节点,mNumNodes保存了挂