精灵动画

本指南讨论如何实现动画精灵并使用相关的 API。

图像表单

Corona 中所有动画精灵的基础是**图像表单**。这可以比作一张纸,您可以在上面绘制动画对象(一个或多个)的各个帧。根据框架的不同,这也可以称为精灵表单、纹理图集或图像映射。Corona 使用**图像表单**术语(以及通过 graphics.newImageSheet() 创建的对象),因为它们的用法不限于动画精灵。事实上,您也可以将图像表单用于从图像表单的一部分中选取的静态图像(通常应该这样做)。有关图像表单的更多信息,请参阅图像表单指南。

下图是名为 `sprites-cat-running.png` 的正在奔跑的猫的示例图像表单。该表单由按特定顺序排列的八个“帧”组成。从概念上讲,动画从左上角的帧开始,前进到下一帧(在其右侧),当到达当前行的末尾时换到下一行,最后在整个序列完成后停止(或重复)。

2048
512

要在 Corona 中配置此图像表单,首先设置一个具有各种属性的索引表。以下示例使用大小一致的帧,但精灵也可以使用帧紧密排列、优化排列的图像表单(请参阅 graphics.newImageSheet() 的文档)。

local sheetOptions =
{
    width = 512,
    height = 256,
    numFrames = 8
}

在此表中,`width` 和 `height` 指定每个帧的像素尺寸。由于有 4 帧宽,并且图像表单的总宽度为 `2048` 像素,因此每帧宽 `512` 像素。类似地,由于有 2 行高,并且表单的总高度为 `512` 像素,因此每帧高 `256` 像素。

下一个参数 `numFrames` 指定图像表单上存在的帧总数。由于奔跑的猫显然有 8 帧动画,因此该值应设置为 `8`。

声明此选项表后,可以通过 graphics.newImageSheet() API 创建图像表单。图像表单文件名应作为第一个参数传递,`options` 表作为第二个参数传递。

local sheet_runningCat = graphics.newImageSheet( "sprites-cat-running.png", sheetOptions )

动画序列

所有动画精灵都需要至少一个命名**序列**,声明为连续帧或非连续帧。

连续帧

最基本的序列是连续帧。它接受一个序列名称、起始帧索引、帧数、动画的可选持续时间以及两个可选的循环参数。

-- sequences table
local sequences_runningCat = {
    -- consecutive frames sequence
    {
        name = "normalRun",
        start = 1,
        count = 8,
        time = 800,
        loopCount = 0,
        loopDirection = "forward"
    }
}

`name` 参数是必需的,可用于将精灵设置为该序列。`start` 和 `count` 参数也是必需的 — 由于奔跑的猫共有 8 帧,因此起始帧可以设置为 `1`,计数设置为 `8`。这告诉序列从第一帧开始并连续播放所有帧直到结束。

接下来,可选的 `time` 参数定义序列的总持续时间(以毫秒为单位)。可以省略此参数,在这种情况下,动画将以应用程序的帧速率进行动画处理(每个时间步一帧)。

`loopCount` 参数定义序列应循环(重复)的次数。将其设置为任何正整数以将序列循环该次数。或者,要无限循环序列,请将 `loopCount` 设置为 `0`。如果设置了循环,您还可以包含 `loopDirection` 参数。设置为 `“forward”` 将从头到尾循环序列,而设置为 `“bounce”` 将从头到尾播放序列,然后反向播放回起始帧。

非连续帧

序列也可以使用非连续帧来定义。此模型接受与上述大多数相同的参数,但它需要一个 `frames` 表,而不是起始帧和帧数。此表是一个逗号分隔的帧索引列表,表示图像表单中的帧。

-- sequences table
local sequences_runningCat = {
    -- non-consecutive frames sequence
    {
        name = "fastRun",
        frames = { 1,3,5,7 },
        time = 400,
        loopCount = 0,
        loopDirection = "forward"
    }
}

多个序列

序列数据表可以(并且通常会)包含多个序列。这允许您在一个位置定义精灵的所有序列,然后根据序列 `name` 参数设置或更改精灵的序列。

要声明多个序列,只需包含多个以逗号分隔的序列表

-- sequences table
local sequences_runningCat = {
    -- first sequence (consecutive frames)
    {
        name = "normalRun",
        start = 1,
        count = 8,
        time = 800,
        loopCount = 0
    },
    -- next sequence (non-consecutive frames)
    {
        name = "fastRun",
        frames = { 1,3,5,7 },
        time = 400,
        loopCount = 0
    },
}
注意
  • 多序列设置中的第一个序列被视为默认序列。创建精灵对象时,将使用默认序列,除非您显式更改序列(请参阅下面的精灵控制方法部分)。

  • 对于多序列设置,您不限于使用来自一个图像表单的帧 — 实际上,每个序列都可以访问唯一的图像表单。为此,只需将 `sheet` 参数添加到任何序列并将其值设置为任何预先声明的 图像表单。有关完整示例,请参阅 display.newSprite()

精灵对象

设置图像表单和序列后,可以使用 display.newSprite() API 创建新的 精灵对象

display.newSprite( [parent,] imageSheet, sequenceData )

对于此 API,`parent` 参数是可选的,表示要在其中插入精灵的显示组。`imageSheet` 参数定义精灵的默认图像表单,`sequenceData` 是包含精灵所有序列的表。

在本指南的上下文中,精灵声明如下所示

local runningCat = display.newSprite( sheet_runningCat, sequences_runningCat )

此行将创建一个名为 `runningCat` 的 显示对象,可以移动、旋转、过渡、链接到 物理主体等 — 并且因为它也是一个 精灵对象,所以它获得了下面概述的所有精灵 控制方法精灵属性

精灵控制方法

精灵库提供了四种主要的控制方法,可用于控制精灵的播放

精灵属性

所有精灵对象都具有各种属性。您甚至可以修改特定精灵的相对动画速度。这些属性如下:

精灵事件

精灵系统可以通过实现精灵侦听器函数来检查 精灵事件。这允许您检测动画何时开始播放、动画何时结束、何时循环等。

要将精灵事件侦听器添加到特定精灵,请使用标准的 object:addEventListener() 方法,并将 `eventName` 属性设置为 `“sprite”` 并引用侦听器函数

object:addEventListener( "sprite", spriteListener )

添加事件侦听器后,`spriteListener` 函数将在动画期间的特定 阶段 被调用

使用这些阶段,假设您希望 `runningCat` 精灵循环播放 `normalRun` 序列的 4 个周期,然后更改为 `fastRun` 序列并无限循环。首先,必须通过将 `loopCount` 更改为 `4` 来修改 `normalRun` 序列。这允许您在所有 4 个循环完成后检测 `ended` 阶段。

local sequences_runningCat = {
    {
        name = "normalRun",
        start = 1,
        count = 8,
        time = 800,
        loopCount = 4
    },
    {
        name = "fastRun",
        frames = { 1,3,5,7 },
        time = 400,
        loopCount = 0
    },
}

接下来,编写侦听器函数并将事件侦听器添加到 `runningCat` 对象。您可以在创建精灵对象后包含此代码,因为事件侦听器是通过单独的命令添加的,而不是在精灵实例化期间声明的。

-- sprite listener function
local function spriteListener( event )

    local thisSprite = event.target  -- "event.target" references the sprite

    if ( event.phase == "ended" ) then  
        thisSprite:setSequence( "fastRun" )  -- switch to "fastRun" sequence
        thisSprite:play()  -- play the new sequence
    end
end

-- add the event listener to the sprite
runningCat:addEventListener( "sprite", spriteListener )

请注意,精灵侦听器将**所有**阶段传输到侦听器函数,因此您有责任使用条件子句并在动画序列中出现特定阶段时执行适当的操作。在上面的示例中,仅检测到 `ended` 阶段,该阶段发生在 `normalRun` 序列的 4 个完整循环之后。当该序列结束时,将设置并播放 `fastRun` 序列,并且由于它无限循环,因此将不会再出现 `ended` 阶段。