给精灵分组
分组让你能够让你创建游戏场景,并且像一个单一单元那样管理相似的精灵图。Pixi有一个对象叫 Container
,它可以帮你做这些工作。让我们弄清楚它是怎么工作的。
想象一下你想展示三个精灵:一只猫,一只刺猬和一只老虎。创建它们,然后设置它们的位置 - 但是不要把它们添加到舞台上。
//The cat
let cat = new Sprite(id["cat.png"]);
cat.position.set(16, 16);
//The hedgehog
let hedgehog = new Sprite(id["hedgehog.png"]);
hedgehog.position.set(32, 32);
//The tiger
let tiger = new Sprite(id["tiger.png"]);
tiger.position.set(64, 64);
让后创建一个animals
容器像这样去把他们聚合在一起:
let animals = new Container();
然后用 addChild
去把精灵图 添加到分组中 。
animals.addChild(cat);
animals.addChild(hedgehog);
animals.addChild(tiger);
最后把分组添加到舞台上。
app.stage.addChild(animals);
(你知道的,stage
对象也是一个Container
。它是所有Pixi精灵的根容器。)
这就是上面代码的效果:
你是看不到这个包含精灵图的animals
分组的。它仅仅是个容器而已。
不过你现在可以像对待一个单一单元一样对待animals
分组。你可以把Container
当作是一个特殊类型的不包含任何纹理的精灵。
如果你需要获取animals
包含的所有子精灵,你可以用它的children
数组获取。
console.log(animals.children)
//Displays: Array [Object, Object, Object]
这告诉你animals
有三个子精灵。
因为animals
分组跟其他精灵一样,你可以改变它的x
和y
的值,alpha
, scale
和其他精灵的属性。所有你改变了的父容器的属性值,都会改变它的子精灵的相应属性。所以如果你设置分组的x
和y
的位置,所有的子精灵都会相对于分组的左上角重新定位。如果你设置了 animals
的x
和y
的位置为64会发生什么呢?
animals.position.set(64, 64);
整个分组的精灵都会向右和向下移动64像素。
animals
分组也有它自己的尺寸,它是以包含的精灵所占的区域计算出来的。你可以像这样来获取width
和height
的值:
console.log(animals.width);
//Displays: 112
console.log(animals.height);
//Displays: 112
如果你改变了分组的宽和高会发生什么呢?
animals.width = 200;
animals.height = 200;
所有的孩子精灵都会缩放到刚才你设定的那个值。
如果你喜欢,你可以在一个 Container
里嵌套许多其他Container
,如果你需要,完全可以创建一个更深的层次。然而,一个 DisplayObject
(像 Sprite
或者其他 Container
)只能一次属于一个父级。如果你用 addChild
让一个精灵成为其他精灵的孩子。Pixi会自动移除它当前的父级,这是一个不用你操心的有用的管理方式。
局部位置和全局位置
当你往一个Container
添加一个精灵时,它的x
和y
的位置是 相对于分组的左上角 的。这是精灵的局部位置,举个例子,你认为这个猫在这张图的哪个位置?
让我们看看:
console.log(cat.x);
//Displays: 16
16?是的!这因为猫的只往分组的左上角偏移了16个像素。16是猫的局部位置。
精灵图还有 全局位置 。全局位置是舞台左上角到精灵锚点(通常是精灵的左上角)的距离。你可以通过toGlobal
方法的帮助找到精灵图的全局位置:
parentSprite.toGlobal(childSprite.position)
这意味着你能在animals
分组里找到猫的全局位置:
console.log(animals.toGlobal(cat.position));
//Displays: Object {x: 80, y: 80...};
上面给你返回了x
和y
的值为80。这正是猫相对于舞台左上角的相对位置,也就是全局位置。
如果你想知道一个精灵的全局位置,但是不知道精灵的父容器怎么办?每个精灵图有一个属性叫parent
能告诉你精灵的父级是什么。在上面的例子中,猫的父级是 animals
。这意味着你可以像如下代码一样得到猫的全局位置:
cat.parent.toGlobal(cat.position);
即使你不知道猫的当前父级是谁,上面的代码依然能够正确工作。
这还有一种方式能够计算出全局位置!而且,它实际上最好的方式,所以听好啦!如果你想知道精灵到canvas左上角的距离,但是不知道或者不关心精灵的父亲是谁,用getGlobalPosition
方法。这里展示如何用它来找到老虎的全局位置:
tiger.getGlobalPosition().x
tiger.getGlobalPosition().y
它会给你返回x
和y
的值为128。 特别的是,getGlobalPosition
是高精度的:当精灵的局部位置改变的同时,它会返回给你精确的全局位置。我曾要求Pixi开发团队添加这个特殊的特性,以便于开发精确的碰撞检测游戏。(谢谢Matt和团队真的把他加上去了!)
如果你想转换全局位置为局部位置怎么办?你可以用toLocal
方法。它的工作方式类似,但是通常是这种通用的格式:
sprite.toLocal(sprite.position, anyOtherSprite)
用 toLocal
找到一个精灵和其他任何一个精灵之间的距离。这段代码告诉你如何获取老虎的相对于猫头鹰的局部位置。
tiger.toLocal(tiger.position, hedgehog).x
tiger.toLocal(tiger.position, hedgehog).y
上面的代码会返回给你一个32的x
值和一个32的y
值。你可以在例子中看到老虎的左上角和猫头鹰的左上角距离32像素。
使用 ParticleContainer 分组精灵
Pixi有一个额外的,高性能的方式去分组精灵的方法称作:ParticleContainer
(PIXI.ParticleContainer
)。任何在ParticleContainer
里的精灵都会比在一个普通的Container
的渲染速度快2到5倍。这是用于提升游戏性能的一个很棒的方法。
可以像这样创建 ParticleContainer :
let superFastSprites = new PIXI.particles.ParticleContainer();
然后用 addChild
去往里添加精灵,就像往普通的 Container
添加一样。
如果你决定用ParticleContainer
你必须做出一些妥协。在 ParticleContainer
里的精灵图只有一小部分基本属性:x
, y
, width
, height
, scale
, pivot
, alpha
, visible
- 就这么多。而且,它包含的精灵不能再继续嵌套自己的孩子精灵。 ParticleContainer
也不能用Pixi的先进的视觉效果像过滤器和混合模式。每个ParticleContainer
只能用一个纹理(所以如果你想让精灵有不同的表现方式你将不得不更换雪碧图)。但是为了得到巨大的性能提升,这些妥协通常是值得的。你可以在同一个项目中同时用 Container
和 ParticleContainer
,然后微调一下你自己的优化。
为什么在 Particle Container
的精灵图这么快呢?因为精灵的位置是直接在GPU上计算的。Pixi开发团队正在努力让尽可能多的雪碧图在GPU上处理,所以很有可能你用的最新版的Pixi的 ParticleContainer
的特性一定比我现在在这儿描述的特性多得多。查看当前 ParticleContainer
文档以获取更多信息。
当你创建一个 ParticleContainer
,有四个参数可以传递, size
, properties
, batchSize
和 autoResize
。
let superFastSprites = new ParticleContainer(maxSize, properties, batchSize, autoResize);
默认的maxSize
是 15,000。所以,如果你需要包裹更多的精灵,把它设置为更高的数字。配置参数是一个拥有五个布尔值的对象:scale
, position
, rotation
, uvs
和 alpha
。默认的值是 position
为 true
,其他都为 false
。这意味着如果你想在 ParticleContainer
改变精灵的rotation
, scale
, alpha
, 或者 uvs
,你得先把这些属性设置为 true
,像这样:
let superFastSprites = new ParticleContainer(
size,
{
rotation: true,
alphaAndtint: true,
scale: true,
uvs: true
}
);
但是,如果你感觉你不需要用这些属性,就保持它们为 false
以实现出更好的性能。
uvs
是什么呢?只有当它们在动画时需要改变它们纹理子图像的时候你需要设置它为 true
。(想让它工作,所有的精灵纹理需要在同一张雪碧图上。)
(注意:UV mapping 是一个3D图表展示术语,它指纹理(图片)准备映射到三维表面的x
和y
的坐标。U
是 x
轴, V
是 y
轴。WebGL用 x
, y
和 z
来进行三维空间定位,所以 U
和 V
被选为表示2D图片纹理的 x
和 y
。)
(我真不知道最后两个参数干什么用的,就是batchSize
和 autoResize
,如果你知道,就赶紧提个Issue吧!)