精灵
当我们的舞台有了场景,但是,没有显示出什么?
这时,我们可以添加一些精灵(Sprite
),你可以控制它们的位置、大小,以及其他很有用的属性来做出一些创造性的交互和动画图形。学会制作和操作 Sprite
是非常重要的。如果你知道如何创建精灵、添加它们到场景中,这只是创作互动动画的入门。
Tiny.js 有一个创建精灵的万能类 => Sprite
,有三种主要的方式来创建它们:
- 使用一张单独的图片文件;
- 使用
tileset
中的子图片; - 使用纹理集(
texture atlas
):定义了图片大小、位置的 JSON 文件
使用 tileset
你已经知道如何通过一张图片来创建精灵,但是,作为互动应用的设计者,一般会使用雪碧图(或称 tileset
)来聚合小图片。下面举一个简单的例子来阐述 tileset 的使用姿势。
这个 tileset 的尺寸是 492*486 像素,你可以使用这里的任意一个地鼠,只需要定义一个和要提取的地鼠尺寸一致的矩形区域。下面我们来提取被砸中的"支地鼠"(左起第二个)。
首先,使用 Tiny.Loader
加载这张 tileset 图片;在加载成功后,通过 Tiny.TextureCache
取到纹理实例,再使用 Tiny.Rectangle
初始化一个矩形,矩形位置、尺寸就是"支地鼠"在雪碧图中的位置、尺寸;然后,将纹理实例的 frame
属性设置为这个矩形;最后,使用纹理实例通过 Tiny.Sprite
创建精灵显示出来。代码如下:
var imgUrl = 'https://zos.alipayobjects.com/rmsportal/gkOPpvvLDjYGZzqJYZKD.png';
Tiny.Loader.add(imgUrl).load(function() {
var antTexture = Tiny.TextureCache[imgUrl];
var rect = new Tiny.Rectangle(166, 2, 160, 158);
antTexture.frame = rect;
var antSprite = new Tiny.Sprite(antTexture);
app.run(antSprite);
});
那么,这是如何工作的?
Tiny.Rectangle
是用来创建矩形,有四个入参,前两个定义了矩形的 x
和 y
的位置值,后两个参数定义了矩形的 width
和 height
。下面是定义一个 Rectangle
对象的姿势:
var rect = new Tiny.Rectangle(x, y, width, height);
一个矩形对象实际上就是一个数据媒介,在这里,它定义着 tileset 上子图的位置和区域,Texture
类的 frame
属性的类型就是任何 Rectangle
对象,frame
通过 Rectangle
的区域裁剪出所需的纹理。
var rect = new Tiny.Rectangle(166, 2, 160, 158);
antTexture.frame = rect;
你就可以使用裁剪出来的纹理,通过 Sprite
类直接构建出精灵来:
var antSprite = new Tiny.Sprite(antTexture);
实际场景中,我们经常会用到 tileset
,通过这种方式创建精灵效率还是低下。
接下来,我们再看看第三种高级姿势。
使用纹理集
如果你正在开发一款稍复杂的互动应用,你一定希望能够快速、有效的通过 tileset 来创建精灵,纹理集在这里就发挥作用了。
Tiny 提供纹理集生成工具,配置好 tiny-app.config.js
后,只需使用工具 tiny-cli 在工程目录下执行 tiny resource
即可。
子图集目录:
tiny-app.config.js
的配置:
module.exports = {
...
// 生成的资源配置文件
resourceName: 'Resource.js',
tileset: [{
// 合并到 tileset 中的子图目录
fold: 'res/images/mole',
name: 'mole_tile'
}]
};
在工程目录下执行 tiny resource
后生成两个文件:mole_tile.json
和 mole_tile.png
,json 文件内容如下:
{
"meta": {
"image": "mole_tile.png",
"size": {"w":492,"h":486},
"scale": "1"
},
"frames": {
"ali_mole.png": // frame id
{
"frame": {"x":2,"y":2,"w":160,"h":158},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":160,"h":158},
"sourceSize": {"w":160,"h":158}
},
...
}
}
同时,生成后的文件会自动添加到资源配置文件(即 src/Resource.js
)的 window.RESOURCES
对象中:
var RESOURCES = {
...
// mole,
"s_mole_tile_json": "res/images/mole_tile.json",
"s_mole_tile_png": "res/images/mole_tile.png",
...
};
看完上面的介绍,我们了解了如何创建一个纹理集,现在,我们看看如何使用。
既然是资源,那就少不了 Tiny.Loader
。加载器会自动识别 json 文件,根据 json 里描述的属性创建出纹理,使用的时候直接查询纹理缓存 Tiny.TextureCache['..']
,唯一标识就是 frame id。
Tiny.Loader.add('https://gw.alipayobjects.com/as/g/tiny/resources/1.0.0/images/tiles/mole_tile.json').load(function() {
var aliMoleHitTexture = Tiny.TextureCache['ali_mole_hit.png'];
var dcMoleTexture = Tiny.TextureCache['dc_mole.png'];
var aliMoleHitSprite = new Tiny.Sprite(aliMoleHitTexture);
var dcMoleSprite = new Tiny.Sprite(dcMoleTexture);
var container = new Tiny.Container();
container.addChild(aliMoleHitSprite);
container.addChild(dcMoleSprite);
dcMoleSprite.setPositionX(150);
container.setPivot(container.width / 2, container.height / 2);
container.setPosition(Tiny.WIN_SIZE.width / 2, 100);
app.run(container);
});
Tips
- 纹理集是一个 JSON 数据文件,它包含 tileset 图片中各个子图的名称、位置和大小等属性;
- 使用纹理集,你不用关心任何顺序问题,同时,你的代码里也不会出现图片大小、尺寸的硬编码了;
- 如果你需要更改某个图片,只需要替换那个子图,然后通过
tiny resource
命令重新生成,不用改代码;
精灵集
更多的场景我们希望操作一组精灵集,就在刚刚,我们用 Tiny.Container
包裹了两个地鼠,并对它们整体设置 pivot
和 position
。
现在,我们再来分解操作三个地鼠,创建后再分别设置它们的位置。
// 支地鼠
var aliMole = new Tiny.Sprite(Tiny.TextureCache['ali_mole.png']);
aliMole.setPosition(40);
// 堵车鼠
var dcMole = new Tiny.Sprite(Tiny.TextureCache['dc_mole.png']);
dcMole.setPosition(80);
// 排队鼠
var pdMole = new Tiny.Sprite(Tiny.TextureCache['pd_mole.png']);
pdMole.setPosition(120);
接着,创建 moles
容器来组合它们到一起:
var moles = new Tiny.Container();
通过 addChild
方法把三个地鼠添加进去:
moles.addChild(aliMole);
moles.addChild(dcMole);
moles.addChild(pdMole);
最后,把这个组合添加到舞台上:
app.run(moles);
你只能看到三只地鼠,但是看不到地鼠集合 moles 任何的表现,因为它只是一个容器。
现在,你可以操作这个集合,就像操作一个对象,你可以认为 Tiny.Container
就是一个没有独立纹理的特殊精灵,你可以直接使用它的所有属性和方法。
例如,我想要获取 moles
下的所有子集,调用它数组格式的属性 children
即可:
console.log(moles.children);
//(3) [Sprite, Sprite, Sprite]
//0: Sprite
//1: Sprite
//2: Sprite
//length: 3
这就告诉了我们 moles
有三个子精灵。
我们也可以更改 x
和 y
值,alpha
,scale
等等所有的属性,更改父集的属性,它的子集也会相对更改。比如:重设了父集的位置 x
、y
,那么它所有的子集也会相对父集左上角的位置进行位移,我们设置 moles
的 x
和 y
都为 -40 时会是什么样?
moles.setPosition(-40);
整个组都上移了 40 像素,左移了 40 像素。
moles
组同样也有自己的尺寸,这取决于它所包含的子集的集合区域,你可以使用 width
和 height
来获取:
console.log(moles.width);
//240
console.log(moles.height);
//238
如果你更改了 moles
的宽高?
moles.width = 360;
moles.height = 360;
所有的地鼠都跟随变化缩放了。
你可以让一个 Container
包含很多的 Container
,不论有多少层。但是,一个显示类(DisplayObject
)仅仅只能拥有一个父集,如果你给一个父集 addChild
一个已有父集的显示对象,那么这个显示对象会自动从原来的父集移除掉。