神马是Sprite Sheets?
Sprite sheet是把多个帧打包在一个文本图片中,来实现2D动画效果。这提供了对纹理内存更加高效的利用,在移动设备上内存是非常有限的,并且也可以最小化加载时间。
Corona支持两种sprite sheet:1、动画帧的大小和位置都一致;2、动画帧的大小和位置都不一致。在前一种情况,你只要向Corona提供在sprite sheet图片文件中每一帧的宽度和高度,就可以创建sprite sheet的新的内部表现形式。下面这张图片(来自 JungleScene 范例工程),是使用规格统一的帧的sprite sheet的一个例子。
在另一个例子中,在sprite sheet中每个帧的大小和位置,被放在另外的数据文件中被描述,这个文件可使用一些sprite sheet生成工具(例如 Zwoptex or TexturePacker)来导出。Corona让你很容易的从一个sprite sheet图片和相关文件来创建一个内部的sprite sheet对象。现在让我们看看关于如果用这两种sprite sheet工作的例子。下面这个sprite sheet(在 HorseAnimation 的范例工程中)就包含了不一致大小和位置的帧。
Corona也包含了采用多序列的复杂角色动画的构造器,并且优先使用基于时间轴而不是基于帧的序列回放方法,所以动画在更慢的设备上,也会保持一样的播放周期。基于时间轴的序列,允许你单独选择并调整每个序列的帧率,而不用把动画的速度锁定为应用程序的全局帧率。
同一个时间可能有超过一个sprite实例在stage上播放,也许周期和位置都不相同。一个sprite动画的行为看上去和其他任何Corona的display object一样--它可能被添加到一个组或被变换,甚至被用于一个Box2D物理对象。
JungleScene 的范例工程展示了使用两个不同的sprite sheet(包括大小一致的帧),来创建不同帧率的动画。sprite sheet源图片的例子,可以参看项目目录下的 “greenman.png” 和 “runningcat.png”两个文件。
HorseAnimation 范例工程展示了如何从一个lua数据描述文件和源图片来创建一个sprite sheet的例子,它的帧都是非一致大小和位置的。
小结
对每个动画序列,开发者都需要指定以下事项:
• 源图片 (the sprite sheet)
• 以下中的其一:
• 在sprite sheet中的每一帧的高度和宽度(一致大小的帧的sprite sheet)。
• 一个lua数据描述文件,描述了每一帧的大小,位置和其他属性(非一致大小帧的sprite sheet)。一般这是由一个sprite sheet打包工具来生成的。
• sprite帧的位置 -- 这可能是不连续的!
当绘制一个sprite动画的实例,开发者需要指定:
• 场景中的目标
• 可选的变换,例如旋转/伸缩
• 动画的长度(基于时间轴)
• 循环行为
Sprite API
下面这行代码,使 sprite的特性在 “sprite”名字空间下,变得有效:
require "sprite"
sprite.newSpriteSheet
sprite.newSpriteSheetFromData
这两个函数创建新的sprite sheets。
下面的代码,从包含大小一致的帧当中创建一个新的sprite sheet,但是并没有在显示列表中添加任何东西。
spriteSheet = sprite.newSpriteSheet("image.png", frameWidth, frameHeight)
这里,sprite sheet的帧数被假定为= floor(imageWidth/frameWidth) * floor(imageHeight/frameHeight)。它们被按原始顺序索引:
1 2 3
4 5 6
7 8 9
spriteSheet = sprite.newSpriteSheetFromData( "image.png", spriteData )
第二种形式是,第二个参数传入一个table,用来在源sprite sheet图片中描述帧大小和位置。
下面代码是使用一个sprite sheet描述文件(名叫test.lua)的例子。它定义了一个简单函数,名叫 getSpriteSheetData()。 它返回一个lua table, sprite sheet 中每一帧的大小,位置,和其他属性,都包含这个table里。
-- test.lua
module (...)
function getSpriteSheetData()
local sheet = {
frames = {
{
name = "01.png",
spriteColorRect = { x = 38, y = 38, width = 50, height = 50 },
textureRect = { x = 2, y = 70, width = 50, height = 50 },
spriteSourceSize = { width = 128, height = 128 },
spriteTrimmed = true,
textureRotated = false
},
{
name = "02.png",
spriteColorRect = { x = 38, y = 36, width = 50, height = 52 },
textureRect = { x = 2, y = 242, width = 50, height = 52 },
spriteSourceSize = { width = 128, height = 128 },
spriteTrimmed = true,
textureRotated = false
},
}
}
return sheet
end
下面代码是从源图像文件(“test.png”)和上面的数据文件(“test.lua”),来创建一个新的sprite sheet对象。
1
2
3
4
5
6
7
local sprite = require("sprite")
-- In this case, test.lua is exported from Zwoptex
local test = require("test.lua")
-- Method defined by test.lua that returns table data defining the sprites
local spriteData = test.getSpriteSheetData()
-- Load the sprite sheet in test.png using the sprite definitions from spriteData
local spriteSheet = sprite.newSpriteSheetFromData( "test.png", spriteData )
这两种情况下,创建一个新的sprite sheet对象,并不能实际导致任何东西被添加到显示列表中。为了做到这一点,你需要从你的sprite sheet对象再创建一个sprite(和可选的sprite集)。后面会解释这个概念。
Tip: 你也可以这样写:
local spriteSheet = sprite.newSpriteSheetFromData( "test.png", test.getSpriteSheetData() )
spriteSet = sprite.newSpriteSet(spriteSheet, startFrame, frameCount)
从一个sprite sheet来创建一个新的sprite集。因为一个单独的sprite sheet可能包含多个不相关的游戏角色的图片,一个“sprite集”定义了属于同一个游戏角色的帧的集合,在播放时分开放入不同的动画序列。例如,一个战斗中的游戏角色,可能有不同的动画序列,出拳和出脚,但是这可以被定义在同一个sprite集中。
startFrame 时sprite第一帧的索引数,使用前面 newSpriteSheet() 中定义的索引,frameCount是集里帧的总数。
一个sprite集,是一个lua table,包含一个给定角色的一个或多个动画序列的键。每个sprite集用一个名为“default”的初始序列创建,集中包含所有帧,所以你及可以立即用默认序列,也可以在集中进一步定义动画序列。
sprite.add( spriteSet, "startFlying", startFrame, frameCount, time, [loopCount])
用指定的一些帧,来添加一个名为“startFlying”的序列,到sprite集中。这个序列有 frameCount 个帧,并将播放 time 毫秒。你可以通过改变time参数,来分别控制每个序列的帧率。
可选参数 loopParam 控制循环行为:
• 一个为1或更大的值,用于设置动画序列将要循环的次数。当到达序列的最后一帧时,将会停止播放。
• loopParam为0时(默认值),意味着序列将会无限期循环。
• loopParam为-1时,意味着序列将“弹”回并且只有一次来回。 (1, 2, 3, 2, 1)。在我们3帧的例子里,这将会按照下面的顺序播放: 1, 2, 3, 2, 1, 2, 3, 2, 1 (...) 一直下去。
spriteSheet:dispose()
一个sprite sheet的销毁,并且释放其纹理内存。它内部也在所有的sprite实例上调用 removeSelf(),从stage上删除了它们。所有属于这个sprite sheet的sprite,序列,和集在调用完这个函数后,也将不再有效,并且当它们不再被你应用程序的lua代码引用时,就会被垃圾回收掉。
1
2
3
4
local sprite = require("sprite")
local spriteSheet = sprite.newSpriteSheet("test.png")
-- Later dispose of the sprite sheet and all of its associated sprites, sequences and sets.
spriteSheet:dispose()
si = sprite.newSprite( spriteSet )
创建一个sprite的新实例。一个sprite就是一个DisplayObject。Sprite在一个时间里播放一个动画序列。
si:prepare([sequence])
停止任何当前播放的动画序列,可选参数用来设置新的当前序列,并且也会移动到那个序列的第一帧。不管怎样,这都会重置循环计数。然而,这个函数并没有开始播放当前序列。
si:play()
播放动画序列,从当前帧开始。不重置循环。
si:pause()
停止动画,单帧保持在显示帧的最后一帧上。随后可以通过play()函数来恢复播放。
si:addEventListener("sprite", listener)
当sprite实例动画得到事件时,可以通知 listener。
传给listener的事件,有如下字段:
event.sprite激发这个事件的sprite;它的当前属性也可以通过这个event访问,例如 event.sprite.sequence。
event.phasesprite所处阶段为下面中的一个:
"end" - sprite已停止播放
"loop" - sprite循环 (从最后到第一,或反向)
"next" - sprite'的下一帧已被播放。
Also see "Custom Events" in the Corona API Reference.
Sprite 属性
animating = true/false. 只读.
currentFrame = frame # of animation. 读/写.
sequence = 当前播放序列的名字