pixiJS界面渲染与交互动作
最开始做网页用H5和js做了一些简单的游戏,主要是练习使用js,其界面非常简陋,并且没有专门对移动端进行适配,导致按键盘交互的游戏无法体验。现在逐渐地熟悉了网页开发,想对一些早期的游戏进行重构。前端的游戏框架当然很多,先从2D游戏开始,多方面调查后选择了pixi作为游戏引擎进行开发。
关于pixi
Pixi是一个超快的2D渲染引擎。这意味着什么呢?这意味着它会帮助你用JavaScript或者其他HTML5技术来显示媒体,创建动画或管理交互式图像,从而制作一个游戏或应用。它拥有语义化的,简洁的API接口并且加入了一些非常有用的特性。比如支持纹理贴图集和为精灵(交互式图像)提供了一个简单的动画系统。它也提供了一个完备的场景图,你可以在精灵图层里面创建另一个精灵,当然也可以让精灵响应你的鼠标或触摸事件。
项目地址: https://github.com/pixijs/pixi.js
中文教程: https://github.com/Zainking/learningPixi
开始
创建Application
Pixi拥有一个Pixi应用对象来帮助你创建它。它会自动创建一个<canvas>HTML标签并且计算出怎么去让你的图片在这个标签中显示 。 这个舞台对象将会被当作根容器而使用,它将包裹所有你想用Pixi显示的东西。
PIXI.Application算出了应该使用Canvas还是WebGL去渲染图象,它取决于你正在使用的浏览器支持哪一个。它的参数是一个被称作options的对象。在这儿例子中,它的width 和 height属性已经被设置了,它们决定了canvas的宽和高(单位是像素)。你能够在options对象中使用更多的属性设置 。
如果你需要在你创建canvas标签之后改变它,可以 app.renderer对象进行设置。
<!doctype html>
<meta charset="utf-8">
<title>Displaying the canvas</title>
<body>
<script src="../pixi/pixi.min.js"></script>
<script>
//Create a Pixi Application
let app = new PIXI.Application({
width: 256,
height: 256,
antialiasing: true,
transparent: false,
resolution: 1
}
);
//Add the canvas that Pixi automatically created for you to the HTML document
document.body.appendChild(app.view);
//If you want to make the canvas fill the entire window, you can apply this
//CSS styling:
/*
app.renderer.view.style.position = "absolute"
app.renderer.view.style.width = window.innerWidth + "px";
app.renderer.view.style.height = window.innerHeight + "px";
app.renderer.view.style.display = "block";
*/
//The `renderer.view` is just an ordinary `<canvas>` element.
//Here's how you can reference to add an optional dashed
//border around the canvas
app.renderer.view.style.border = "1px dashed black";
//To resize the canvas
app.renderer.resize(512, 512);
//To change the background color
app.renderer.backgroundColor = 0x061639;
</script>
</body>放置对象
所有你想在画布上显示的东西必须被加进一个被称作 stage的Pixi对象中。你能够像这样使用舞台对象 。 Pixi用WebGL和GPU去渲染图像,所以图像需要转化成GPU可以处理的版本。可以被GPU处理的图像被称作 纹理 。在显示图片之前,需要将普通的图片转化成WebGL纹理。 加载后用stage.addChild方法把它放到Pixi的stage上面去。
//load an image and run the `setup` function when it's done
PIXI.loader
.add("images/cat.png")
.load(setup);
//This `setup` function will run when the image has loaded
function setup() {
//Create the cat sprite
let cat = new PIXI.Sprite(PIXI.loader.resources["images/cat.png"].texture);
//You can also create the `cat` sprite from the texture, like this:
//let cat = new PIXI.Sprite(PIXI.TextureCache["images/cat.png"]);
//Add the cat to the stage
app.stage.addChild(cat);
//If you ever need to, here's how you can clean out WebGL's GPU
//memory manually
/*
Object.keys(TextureCache).forEach(function(texture) {
TextureCache[texture].destroy(true);
});
*/
}这样,路径为images/cat.png的图片就可以加载到Application上显示出来。如果想把cat移走,可以使用app.stage.removeChild(cat), 但是通常,我们都把精灵的visible属性设置成false来让它简单的隐藏。
要调整它的位置,可以使用cat.position.set(x, y),也可以为cat.x与cat.y赋值。宽高则分别用width和height属性,或者用scale.x,scle.y的方法按比例调整宽高,也可以使用cat.scale.set(x,y)更改。
cat.rotation 可以指定旋转角度,cat.anchor.set(x,y)可以指定旋转锚点,锚点以0到1的小数表示,cat.anchor.set(0.5,0.5)即为默认值,以图像中心为锚点旋转。相应地,用cat.pivot则以指定像素的方式指定旋转锚点。
使用别名
可以对你使用频繁的Pixi对象和方法设置一些简略的可读性更强的别名
//Aliases
let Application = PIXI.Application,
loader = PIXI.loader,
resources = PIXI.loader.resources,
Sprite = PIXI.Sprite;
//Create a Pixi Application
let app = new Application({
width: 256,
height: 256,
antialias: true,
transparent: false,
resolution: 1
}
);
//Add the canvas that Pixi automatically created for you to the HTML document
document.body.appendChild(app.view);
//load an image and run the `setup` function when it's done
loader
.add("images/cat.png")
.load(setup);
//This `setup` function will run when the image has loaded
function setup() {
//Create the cat sprite
let cat = new Sprite(resources["images/cat.png"].texture);
//Add the cat to the stage
app.stage.addChild(cat);
}预加载的进度条
Pixi的加载器有一个特殊的progress事件 ,可以这样绑定到相应函数上:PIXI.loader.on("progress", loadProgressHandler);
function loadProgressHandler(loader, resource) {
//Display the file `url` currently being loaded
console.log("loading: " + resource.url);
//Display the percentage of files currently loaded
console.log("progress: " + loader.progress + "%");
//If you gave your files names as the first argument
//of the `add` method, you can access them like this
//console.log("loading: " + resource.name);
}
用css sprite加载
所谓css sprite就是将所有素材都放在一张大图上,而使用的素材则是这个大图的一块区域,这样只要大图加载完成,那么所有素材也就加载完成。如下图示,为jQuery-ui的图标

Pixi内置了一个通用的Rectangle对象 (PIXI.Rectangle),他是一个用于定义矩形形状的通用对象。他需要一些参数,前两个参数定义了x 和y轴坐标位置,后两个参数定义了矩形的width 和 height 。
Pixi的纹理中有一个叫做frame的很有用的属性,它可以被设置成任何的Rectangle对象。frame将纹理映射到Rectangle的维度 。
loader
.add("images/ui-icons_cd0a0a_256x240.png")
.load(setup);
function setup() {
let rectangle = new PIXI.Rectangle(0, 0, 16, 16);
let texture = TextureCache["images/ui-icons_cd0a0a_256x240.png"];
texture.frame = rectangle;
let theIcon = new Sprite(texture);
app.stage.addChild(theIcon);
}纹理贴图集
要向游戏中一次添加多个对象,一种比较快速有效的方法就是纹理贴图集。,
一个纹理贴图集就是一个JSON数据文件,它包含了匹配的PNG雪碧图的子图像的大小和位置。如果你使用了纹理贴图集,那么想要显示一个子图像只需要知道它的名字就行了。你可以任意的排序你的排版,JSON文件会保持他们的大小和位置不变。这非常方便,因为这意味着图片的位置和大小不必写在你的代码里。如果你想要改变纹理贴图集的排版,类似增加图片,修改图片大小和删除图片这些操作,只需要修改那个JSON数据文件就行了,你的游戏会自动给程序内的所有数据应用新的纹理贴图集。你没必要在所有用到它代码的地方修改它。 pixi兼容TexturePacker的JSON格式,类似于如下的json文件:
{"frames": {
"cat.png":
{
"frame": {"x":2,"y":2,"w":64,"h":64},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
"hedgehog.png":
{
"frame": {"x":68,"y":2,"w":64,"h":64},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
},
"tiger.png":
{
"frame": {"x":134,"y":2,"w":64,"h":64},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
"sourceSize": {"w":64,"h":64},
"pivot": {"x":0.5,"y":0.5}
}},
"meta": {
"app": "http://www.codeandweb.com/texturepacker",
"version": "1.0",
"image": "animals.png",
"format": "RGBA8888",
"size": {"w":200,"h":68},
"scale": "1",
"smartupdate": "$TexturePacker:SmartUpdate:52586866875309c357a59ef94cc3e344:67b70cfeefc06c04b551ab33c8f1fc7a:b00d48b51f56eb7c81e25100fcce2828$"
}
}
用Pixi的loader来加载纹理贴图集 。setup中创建它们,可以使用TextureCache,也可以用resources["images/treasureHunter.json"].textures["frameId.png"],为了方便一般给它起别名然后在方括号中再索引它:
let id = PIXI.loader.resources["images/treasureHunter.json"].textures; frameId = new Sprite(id["frameId.png"]);
移动物体
为app的ticker注册函数,它将会每秒执行60次。
app.ticker.add(delta => gameLoop(delta));
function gameLoop(delta){
//Move the cat 1 pixel
cat.x += 1;
} delta的值代表帧的部分的延迟 ,可以把它添加到cat的位置,让cat的速度和帧率无关 ,它往往只在你的动画没法跟上60帧的速率时候出现(比如游戏运行在很老旧的机器上) 。
也可以用requestAnimationFrame像这样创建
function gameLoop() {
//Call this `gameLoop` function on the next screen refresh
//(which happens 60 times per second)
requestAnimationFrame(gameLoop);
//Move the cat
cat.x += 1;
}
//Start the loop
gameLoop();属性cat.vx与cat.vy能够设定物体移动速度,例如可以这样编写让小猫头碰到边界就反弹的效果:
var cat;
loader
.add("images/cat.png")
.load(setup);
function setup() {
let texture = TextureCache["images/cat.png];
cat = new Sprite(texture);
cat.width=30;
cat.height=30;
cat.vx = 1;
cat.vy = 1;
app.stage.addChild(cat);
app.ticker.add(delta=>gameLoop(delta));
}
function gameLoop(delta)
{
cat.x += cat.vx;
if(cat.x+cat.width>app.view.width || cat.x<0)
{
cat.vx *=-1;
}
cat.y += cat.vy;
if(cat.y+cat.height>app.view.height || cat.y<0)
{
cat.vy *=-1;
}
}
键盘动作
编写这样一个函数,为相应keyCode的键位构造一个key对象。在使用时,只需要指定press和releas方法即可非常方便的设计键盘动作
function keyboard(keyCode) {
let key = {};
key.code = keyCode;
key.isDown = false;
key.isUp = true;
key.press = undefined;
key.release = undefined;
//The `downHandler`
key.downHandler = event => {
if (event.keyCode === key.code) {
if (key.isUp && key.press) key.press();
key.isDown = true;
key.isUp = false;
}
event.preventDefault();
};
//The `upHandler`
key.upHandler = event => {
if (event.keyCode === key.code) {
if (key.isDown && key.release) key.release();
key.isDown = false;
key.isUp = true;
}
event.preventDefault();
};
//Attach event listeners
window.addEventListener(
"keydown", key.downHandler.bind(key), false
);
window.addEventListener(
"keyup", key.upHandler.bind(key), false
);
return key;
} 键盘对象也有 isDown 和 isUp 的布尔值属性,你可以用它们来检查每个按键的状态。
鼠标动作
1.鼠标左键触发事件:
- click:点击事件
- mousedown:鼠标按下
- mousemove:鼠标移动
- mouseout:鼠标移出
- mouseover:鼠标经过
- mouseup:鼠标松开
- mouseupoutside:鼠标按下,移出对象松开
2.鼠标右键触发事件:
- rightclick:点击事件
- rightdown:鼠标按下
- rightup:鼠标松开
- rightupoutside:鼠标按下,移出对象松开
3.触摸屏触发事件:
- touchcancel:触摸系统cancels键
- touchend:触摸结束
- touchendoutside:触摸开始,移出对象松开
- touchmove:触摸移动
- touchstart:触摸开始
4.兼容鼠标和触摸屏的共同触发:
- pointercancel:触发系统cancels键
- pointerdown:触发按下
- pointermove:触发移动
- pointerout:触发移出
- pointerover:触发经过
- pointertap:触发点击
- pointerup:触发松开
一般在应用时,最好是做兼容鼠标和触摸屏的方式,毕竟现在移动端可能市场更大一些。要使对象能响应鼠标动作,需要指定其interactive为true.
例如,编写一个点击猫头让猫头变大的鼠标动作:
var cat;
loader
.add("images/cat.png")
.load(setup);
function setup() {
let texture = TextureCache["images/cat.png"];;
cat = new Sprite(texture);
cat.x=50;
cat.y=50;
cat.width=30;
cat.height=30;
cat.on('pointerdown',OnPointerDown)
.on('pointerup',OnPointerUp);
cat.interactive = true;
app.stage.addChild(cat);
}
var expandRate = 0.2,absoluteWidth,absoluteHeight;
function OnPointerDown()
{
absoluteWidth = this.width*expandRate;
absoluteHeight = this.height*expandRate;
this.x-=absoluteWidth/2;
this.y-=absoluteHeight/2;
this.width+=absoluteWidth;
this.height+=absoluteHeight;
}
function OnPointerUp()
{
this.x+=absoluteWidth/2;
this.y+=absoluteHeight/2;
this.width-=absoluteWidth;
this.height-=absoluteHeight;
}
另外,对物体的拖动也是非常重要的鼠标交互事件。编写一个拖动猫头中心的鼠标动作:
var cat;
loader
.add("images/cat.png")
.load(setup);
function setup() {
let texture = TextureCache["images/cat.png"];;
cat = new Sprite(texture);
cat.x=50;
cat.y=50;
cat.width=30;
cat.height=30;
cat.on('pointerdown', onDragStart)
.on('pointerup', onDragEnd)
.on('pointerupoutside', onDragEnd)
.on('pointermove', onDragMove);
cat.interactive = true;
app.stage.addChild(cat);
}
function onDragStart(event) {
this.data = event.data;
this.alpha = 0.5;
this.dragging = true;
}
function onDragEnd(event) {
this.alpha = 1;
this.dragging = false;
this.data = null;
}
function onDragMove(event) {
if(this.dragging) {
var newPosition = this.data.getLocalPosition(this.parent); //获取鼠标移动的位置
this.position.x = newPosition.x-this.width/2;
this.position.y = newPosition.y-this.height/2;
}
}
以上就是使用pixi进行简单地交互所需要的知识。更多更详细的内容可以看pixi的教程。另外,如果要制作复杂的交互游戏或应用,可能仅使用Pixi还不够,这时就可以利用其它的库来丰富交互体验。