显示对象 — 图片、文本、形状等

Corona 显示对象包含了放置在舞台或显示组内的各种视觉对象。这些对象包括图片、文本、形状、线条、动画精灵等等。

创建显示对象

使用 Corona 的 display 库中的方法可以轻松创建显示对象。

备注
  • 显示对象的行为本质上与普通的 Lua 表类似。这意味着您可以向对象添加自己的属性,只要它们不与保留的属性或方法名称冲突即可。一个小的例外是您不能使用数字索引将显示对象作为数组进行索引。有关更多信息,请参阅本指南末尾的技术说明

  • 大多数显示对象都有一个锚点,默认为对象的中心。相反,默认情况下,显示组不考虑锚点。此外,显示组的默认原点是 `0,0`,它位于舞台的左上角而不是中心。因此,如果您只是将一个非组显示对象放置在舞台上坐标 `0,0` 处,它的中心点将位于舞台的左上角。有关更多信息,请参阅变换和锚点以及组编程指南。

属性和方法

显示对象都是一等公民.您可以使用通用属性和方法移动、旋转、动画(过渡)它们等等.

属性通过点运算符访问。例如,您可以通过编写以下代码将对象的 alpha 值更改为 50%

local myImage = display.newImage( "image.png" )
myImage.alpha = 0.5  --change the alpha property

方法通过冒号运算符执行。例如,您可以通过编写以下代码来平移(移动)对象

local myImage = display.newImage( "image.png" )
myImage:translate( 10, 50 )  --move the object 10 pixels right and 50 pixels down.

显示层次结构

Corona 中的屏幕/显示器由舞台和一个可选的子显示组层次结构组成。显示组是一种特殊的显示对象,可以包含子对象。这使得可以将显示对象组织成组并构建其他组之间的关系。有关此主题的更多信息,请参阅组编程指南。

默认情况下,显示对象会被添加到舞台。但是,您通常需要将显示对象插入到特定的显示组中。这可以通过两种方法完成

内联方法

为方便起见,大多数显示对象都接受显示组作为 API 调用的第一个参数。这会将对象插入到该组中.

local myGroup = display.newGroup()

--create object in 'myGroup'
local myImage = display.newImage( myGroup, "image.png" )

直接方法

直接方法将显示对象插入到指定的组中。此方法也可用于将对象从一个组移动到另一个组。请注意,一个对象不能同时存在于两个组中,因此将其插入到不同的组中也会将其从当前组中移除。

local myGroup = display.newGroup()

--create object on the stage (default)
local myImage = display.newImage( "image.png" )

--insert object into 'myGroup'
myGroup:insert( myImage )
注意

尽管显示组本质上是表,但 Lua 库函数(如 `table.insert()` 和 `ipairs()`)与组不兼容。此外,您不能使用 `#myGroup` 获取显示组中子级的数量。请改用 `myGroup.numChildren`。

对象顺序

在特定显示组中,对象按从后到前的顺序绘制。因此,您创建的第一个对象将位于稍后创建的对象的后面

幸运的是,显示对象的顺序并不是一成不变的。您可以随时更改对象的相对顺序。绘制显示组子级的顺序由数组的顺序决定。使用 `group:insert()` 方法,您可以重新排列对象在其父组中的位置。

local square = display.newRect( myGroup, 0, 0, 100, 100 )  --red square is at the bottom
square:setFillColor( 1, 0, 0 )
local circle = display.newCircle( myGroup, 80, 120, 50 )  --green circle is in the middle
circle:setFillColor( 0, 1, 0 )
local rect = display.newRect( myGroup, 0, 0, 120, 80 )  --blue rectangle is at the top
rect:setFillColor( 0, 0, 1 )

--'square', 'circle', and 'rect' all have same parent ('myGroup')
local parent = square.parent
 
--move 'square' to the top (siblings at higher indices reside above those at lower ones)
--conceptually, this just re-inserts the object at the top of its group
parent:insert( square )
 
--move 'circle' 'below all other siblings
parent:insert( 1, circle )

此外,还可以使用 `object:toBack` 和 `object:toFront` 方法在组内移动对象。

屏幕更新

基本的绘制模型包括执行 Lua 代码和渲染显示层次结构中对象的循环。在此循环中,仅当显示中的对象发生更改时,屏幕才会更新。这些更改是通过添加、删除或更改子显示对象的属性而发生的.

当 Lua 代码块正在执行时,屏幕永远不会更新。因此,如果您在代码块中多次修改显示对象(例如,更新 `x` 位置),则只有最后一次更改(最终的 `x` 设置)会在屏幕更新时反映出来。

对象引用

由于对象可以在层次结构中重新排序,因此使用整数索引访问显示组子级比较脆弱。如果您将子级移到其兄弟姐妹上方,则必须更新代码中的所有整数索引。

在大多数情况下,通过变量名引用显示对象是最简单的。变量可以命名为任何您希望的名称,不能以数字开头或使用 Lua 或 Corona 保留的名称。这些命名规则适用于 Lua 中的所有变量,因此请记住它们。

local yellowDuck = display.newText( "Quack!", 50, 50, "Arial", 60 )  --OK!

local orangeTiger22 = display.newText( "Roar!", 50, 50, "Arial", 60 )  --OK!

local 23dog = display.newText( "Woof!", 50, 50, "Arial", 60 )  --unacceptable! (name begins with a number)

local and = display.newText( "and", 50, 50, "Arial", 60 )  --unacceptable! ('and' is a Lua-reserved term)

另一种选择是将某些显示对象插入到标准 Lua 表中以进行组织。如果您希望引用一组独立于其显示组的对象,则此方法很有用。例如

local squares = display.newGroup()

local redSquare1 = display.newRect( squares, 0, 0, 40, 40 )
local redSquare2 = display.newRect( squares, 0, 0, 40, 40 )
local redSquare3 = display.newRect( squares, 0, 0, 40, 40 )
redSquare1:setFillColor( 1, 0, 0 )
redSquare2:setFillColor( 1, 0, 0 )
redSquare3:setFillColor( 1, 0, 0 )

local whiteSquare1 = display.newRect( squares, 0, 0, 40, 40 )
local whiteSquare2 = display.newRect( squares, 0, 0, 40, 40 )
whiteSquare1:setFillColor( 1 )
whiteSquare2:setFillColor( 1 )

--insert only the red squares into a table
local redSquares = { redSquare1, redSquare2, redSquare3 }

虽然红色方块和白色方块都位于 `squares` 显示组中,但您可以通过循环 `redSquares` 表来仅操作红色方块

for i = 1, #redSquares do
    --manipulate the square at the current index (i)
    redSquares[i].x = redSquares[i].x + 100
    redSquares[i]:scale( 0.5, 0.5 )
end

请注意,如果您使用此方法存储/组织显示对象,则当对象从屏幕上清除时,您必须从表中删除引用.

移除显示对象

由于设备的内存有限,因此在不再需要显示对象时将其从显示层次结构中移除非常重要。这有助于通过减少内存消耗(尤其是纹理内存)以及消除不必要的屏幕绘制来提高整体系统性能.

有两种基本方法可以从显示层次结构中移除显示对象。

直接移除

此方法针对特定显示对象并将其从显示中移除。

display.remove( myObject )

--OR

myObject:removeSelf()

--OR

myGroup:remove( myObject )  --group array index also valid

但是,这些方法都无法完全释放显示对象占用的内存。为了防止内存泄漏,您必须消除对显示对象的所有变量引用。这是通过将引用设置为 `nil` 来实现的。

display.remove ( myObject )
myObject = nil  --set reference to nil!

--OR

myObject:removeSelf()
myObject = nil  --set reference to nil!

--OR

myGroup:remove( myObject )
myObject = nil  --set reference to nil!

组移除

此方法删除显示组中的所有子级 - 您只需删除显示组本身,然后将其引用设置为`nil`即可。

display.remove( myGroup )
myGroup = nil

--OR

myGroup:removeSelf()
myGroup = nil
重要
  • 如上文对象引用部分所述,如果存在指向显示对象的 référen其他变量或引用,则无法将其从内存中完全释放。解决方案是将所有这些外部引用设置为 `nil`。完成后,Lua 就可以释放内存分配。

  • 全局变量永远不会自动从内存中释放,因此如果全局变量指向显示对象,即使该对象不再位于显示层次结构中,它仍将继续占用内存。请记住将对显示对象的所有全局引用设置为 `nil`。

  • 当您移除显示对象时,附加到它的事件侦听器(例如,点击和触摸侦听器)也会从内存中释放。您无需显式移除隔离到该对象的事件侦听器。

  • 应用于对象的过渡应在移除对象之前取消并设置为 `nil`。由于显示对象本质上是 Lua 表,因此一种方便的方法是将过渡设置为显示对象本身的属性。这使您可以轻松地访问和取消它.

技术说明

在本指南的开头附近,我们提到显示对象的行为“本质上”类似于 Lua 表。此规则的一个例外是您不能设置显示对象的元表。这是由于在这种特殊情况下我们的 C++/Lua 集成的性质所致。

Corona 显示对象在内部是原生 C++ 对象。Lua 使用“userdata”实现原生指针的绑定,它设置元表。用户数据元表不能被 Lua 代码替换;这是 Lua 本身定义的措施.

通常,以这种方式绑定到 Lua 的原生对象的行为不像表。Corona 中有几个这样的例子。此类对象可能具有属性和/或方法,但它们不可扩展。相反,Corona 显示对象的行为确实类似于表 - 这是一个方便的功能,另一种选择是提供一个“用户数据”字段来访问与显示对象关联的自定义数据。将此功能直接合并到显示对象中对于最终用户来说更容易且更具扩展性。

本质上,底层原生桥受到 Lua 中允许内容的限制,我们将此架构选择视为 Corona 的基本功能。最终,Corona 是一个 C++/OpenGL 引擎,其框架专为快速开发而设计,这些优势证明了将元表用于显示对象的合理性。