在 Solar2D 中,显示组 是以层次结构组织对象的标准方式。
理解 显示组 对于在 Solar2D 中构建应用程序至关重要。显示组是一种特殊的 显示对象,它可以包含其他显示对象,甚至其他显示组。可以将其想象成一张空白纸,您可以在上面“绘制”图像、文本、形状和动画精灵。
在 Solar2D 中进行应用程序开发时,需要注意的是,显示组不受屏幕边界的限制。实际上,显示组是无限的,并且在所有方向上都延伸到无穷大 — 物理屏幕边缘只是 舞台 的一部分。在 Solar2D 中,舞台可以被认为是父显示组,您创建的新显示组会自动添加为它的子组。
所有显示组,包括 舞台,都围绕一个坐标系旋转。您放置在屏幕上的任何可视对象都将具有一个 x
和 y
坐标,分别指示其水平和垂直位置。
在 Solar2D 中,显示组的默认原点是 0,0
,它位于舞台的0,0
点开始,正 x
值向右延伸,而正 y
值向下延伸(与 笛卡尔 坐标系中的向上延伸不同)。也允许使用负坐标,但如下面的图表所示,它们不会位于屏幕上可见的组部分(黑色区域)内。但是,可以移动组以调整其原点 — 有关更多信息,请参见下面的 组变换。
“空白纸”的比喻有助于理解 Solar2D 的绘制模型。就像您在纸上绘制图形一样,放置在显示组中的 Solar2D 显示对象 将成为该组(纸张)的一部分。
未放置到特定组中的显示对象将成为 舞台 的一部分,但在开发应用程序的过程中,您通常会以特定的分层顺序创建多个显示组。您可以将其想象成“一堆纸”,每个显示组代表堆栈中的一张纸。例如,假设您要模拟具有以下三层(三个显示组)的“风景画”:
这些显示组中的每一个都将依次包含适当的显示对象,从而以正确的分层顺序构成绘画。当然,虽然每一层在比喻中都代表一张纸,但您实际上看不到“纸”本身 — 只需将它们想象成透明的纸张,您可以在上面放置文本、图像等。
创建新的显示组非常简单,如下所示:
local myGroup = display.newGroup()
这将创建一个新的显示组,并将其分配给局部变量 myGroup
。然后,您可以向其添加显示对象
local myGroup = display.newGroup() --Create a rectangle local rect = display.newRect( 0, 0, 40, 40 ) --Insert it into 'myGroup' myGroup:insert( rect )
许多显示对象 API 也接受组作为内联参数。有关
local myGroup = display.newGroup() --Create a rectangle and insert it into 'myGroup' local rect = display.newRect( myGroup, 0, 0, 40, 40 )
您应该以特定顺序创建显示组。就您的代码而言,**首先**声明的组实际上将位于视觉分层顺序中**下一个**组的**后面**。例如,要创建上面讨论的“风景画”,请按如下方式声明三个显示组
local farBackground = display.newGroup() local nearBackground = display.newGroup() --this will overlay 'farBackground' local foreground = display.newGroup() --and this will overlay 'nearBackground'
尽管显示组本质上是表,但 Lua 库函数(如 table.insert()
和 ipairs()
)与组**不兼容**。此外,您无法使用 #myGroup
获取显示组中子对象的數量。请改用 myGroup.numChildren
。
可以通过 display.remove() 或 object:removeSelf() 函数移除组。执行此操作时,组中的所有子对象也将被移除。但是,您仍然必须手动移除与这些子对象关联的变量或其他引用,否则它们将不会从内存中释放。有关更多详细信息,请参阅 显示对象 指南。
local myGroup = display.newGroup() --Create 2 rectangles and insert them into 'myGroup' local rect1 = display.newRect( myGroup, 0, 0, 40, 40 ) local rect2 = display.newRect( myGroup, 30, 30, 60, 60 ) myGroup:removeSelf() --OR display.remove( myGroup ) myGroup = nil
当您修改组的属性时,它的所有子对象都会受到影响。例如,如果您在显示组上设置 alpha 属性,则每个子对象的 alpha 值将乘以组的新 alpha 值。组会自动检测子对象的属性何时发生更改(位置、旋转等)。因此,在下一个渲染过程中,子对象将
组变换以层次结构方式应用于组的子对象。首先应用子对象的变换,然后应用其父对象的变换,然后应用每个祖先的变换,一直到 舞台。因此,组中的子对象是相对于父组的位置进行定位的。当您修改组的变换(移动/缩放/旋转)时,它会影响子对象的变换。
在下图中,黑色区域表示理论上的 Solar2D 内容区域(横向),橙色线条的交点表示组的原点。请注意,此原点始终默认为 0,0
为了进行测试,在 100,100
处绘制了一个红色矢量对象,这表示其中心位置,因为 显示对象 具有默认的中心 锚点。
local myGroup = display.newGroup() local myBox = display.newRect( 100, 100, 80, 80 ) myBox:setFillColor( 1, 0, 0, 0.8 ) myGroup:insert( myBox )
如果将组移动(变换)到新的 x
和 y
位置,则其原点将移动到该点
myGroup.x = 50 myGroup.y = 50
请注意,红色框会随着组(其父对象)一起移动。但是,对象的**固有** x
和 y
位置**不会**更改 — 即使该框显示在**内容**位置 150,150
处,它仍然保持在 100,100
处。这是因为 Solar2D 管理显示对象相对于其父组的位置。
要获取对象在内容坐标中的实际位置,而不考虑移动/缩放/旋转的组,请使用 object:localToContent() 函数
local actualBoxX, actualBoxY = myBox:localToContent( 0,0 ) print( actualBoxX, actualBoxY )
对于普通的 显示对象(例如图像或矢量形状),其 锚点 控制其几何图形相对于其**原点**的定位方式。当您更改普通显示对象的锚点时,其原点**不会**更改。相反,它的几何图形会相对于其原点移动。有关更多信息,请参阅 变换和锚点 指南。
相反,显示组 默认情况下不考虑锚点。这是因为显示组,根据基本原则,是无限的,并且在所有方向上都延伸到无穷大。但是,它们确实具有一个默认为 0,0
的 x
和 y
位置
或者,可以在显示组上使用锚点。为了演示此方法,应将另一个显示对象添加到 组变换 部分中概述的示例中
local myGroup = display.newGroup() local myBox = display.newRect( 100, 100, 80, 80 ) myBox:setFillColor( 1, 0, 0, 0.8 ) myGroup:insert( myBox ) myGroup.x = 50 myGroup.y = 50 --Add a smaller blue box local blueBox = display.newRect( 50, 50, 50, 50 ) blueBox:setFillColor( 0, 0, 1, 0.8 ) myGroup:insert( blueBox )
现在,将组的锚点设置为左上角(anchorX 和 anchorY 均设置为 0
)
myGroup.anchorX = 0 myGroup.anchorY = 0
如果刷新项目,则不会出现**视觉**变化,因为默认情况下,显示组不考虑锚点。但是,您可以通过将显示组的 anchorChildren 属性设置为 true
来实现锚点行为。
在探讨 anchorChildren
属性的工作原理之前,请检查下图中的理论边界框(不透明白色)— 此框将用作理解组上锚点的可视辅助。请注意,边界框会考虑组中**所有**显示对象的最大顶部、右侧、底部和左侧点
现在,将 anchorChildren
属性设置为 true
myGroup.anchorChildren = true
请注意,整个组边界将移动到组的**当前原点**(如前所述,为 50,50
)。因为组的锚点设置为 0,0
如果整个组原点移动,则对象将按预期移动
myGroup.x = 150
如果将锚点重置为右上角 (1,0
),则该组将在当前原点 150,50
处重新定位
myGroup.anchorX = 1 myGroup.anchorY = 0
本质上,当显示组的 anchorChildren
属性设置为 true
时,所有子对象都将偏移相同的量。该偏移量是根据组中所有子对象的边界框计算的。实际上,子对象被视为一个单元,组的原点是该单元的锚点。
使用 anchorChildren
的替代方法是将组放置在另一个组(“父组”)中。更改此父组的位置、旋转或缩放将产生类似的行为。
一种称为 容器 的特殊类型的组可以将组的边界限制为
Solar2D 将剔除屏幕边界之外的子对象。