PixiJS是一个轻量级的2D渲染引擎,它能自动侦测使用WebGL仍是Canvas来建立图形。这个库常常被用来制做HTML5游戏以及有复杂交互的H5活动页。javascript
注意:本文使用pixi最新的v5版本,同时使用Parcel进行模块化打包html
pixi.js
v5版本默认使用webgl渲染,若是但愿能够回退到canvas,须要使用pixi.js-legacy
,详情见issue前端
项目初始化java
mkdir learn-pixi cd learn-pixi npm init -y 复制代码
安装依赖git
npm i pixi.js -save
npm i parcel-bundler -save-dev
复制代码
根目录建立index.html
github
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>learn-pixi</title> </head> <body> <script src="./src/index.js"></script> </body> </html> 复制代码
根目录建立src
目录,新建src/index.js
web
alert('pixi'); 复制代码
修改package.json
npm
"scripts": { "dev": "parcel index.html -p 8080", "build": "parcel build index.html" } 复制代码
运行npm run dev
,访问 http://localhost:8080/ 便可看到效果json
index.js
canvas
import { Application } from 'pixi.js'; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); // app.view就是个canvas元素,挂载到页面上 document.body.appendChild(app.view); 复制代码
页面上就出现了一个300*300的蓝色矩形,矩形是由pixi.js建立的canvas渲染的。
咱们能够继续建立新的图形,而后渲染到canvas里
import { Application, Graphics } from 'pixi.js'; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); // 建立一个半径为32px的圆 const circle = new Graphics(); circle.beginFill(0xfb6a8f); circle.drawCircle(0, 0, 32); circle.endFill(); circle.x = 130; circle.y = 130; // 添加到app.stage里,从而能够渲染出来 app.stage.addChild(circle); 复制代码
咱们还能够渲染图片
import { Application, Sprite } from 'pixi.js'; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); // 建立一个图片精灵 const avatar = new Sprite.from('http://anata.me/img/avatar.jpg'); // 图片宽高缩放0.5 avatar.scale.set(0.5, 0.5); app.stage.addChild(avatar); 复制代码
咱们让这个图片精灵变得能够交互:点击图片后,图片透明度变成0.5
const avatar = new Sprite.from('http://anata.me/img/avatar.jpg'); avatar.scale.set(0.5, 0.5); // 居中展现 avatar.x = 100; avatar.y = 100; // 可交互 avatar.interactive = true; // 监听事件 avatar.on('click', () => { // 透明度 avatar.alpha= 0.5; }) app.stage.addChild(avatar); 复制代码
咱们还能让图片一直旋转
const avatar = new Sprite.from('http://anata.me/img/avatar.jpg'); avatar.scale.set(0.5, 0.5); avatar.x = 150; avatar.y = 150; // 修改旋转中心为图片中心 avatar.anchor.set(0.5, 0.5) app.stage.addChild(avatar); app.ticker.add(() => { // 每秒调用该方法60次(60帧动画) avatar.rotation += 0.01; }) 复制代码
pixi
有几个重要的Class:
const app = new Application({ width: 300, height: 300 }); 复制代码
Application
是pixi提供的一个工具方法,它能自动建立renderer,ticker 和container,咱们一般使用该方法快速建立应用。
app.stage
是一个Container
的实例,做为最底层的舞台(stage),全部要渲染的图形都应放在它的内部
const app = new Application({ width: 300, height: 300 }); // 添加不一样的图形 app.stage.addChild(circle1); app.stage.addChild(circle2); 复制代码
咱们也能够建立本身的Container
,自定义的Container一般用来分组
import { Application, Container, Graphics } from 'pixi.js'; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); // 自定义Container const myContainer = new Container(); // 相对于根节点偏移 myContainer.position.set(40, 40); let rectangle = new Graphics(); rectangle.beginFill(0x000000); rectangle.drawRect(0, 0, 64, 64); rectangle.endFill(); let rectangle2 = new Graphics(); rectangle2.beginFill(0xFFFFFF); rectangle2.drawRect(0, 0, 64, 64); rectangle2.endFill(); // 相对于自定义Container偏移 rectangle2.position.set(20, 20); // 两个图形加到自定义Container里 myContainer.addChild(rectangle); myContainer.addChild(rectangle2); // 自定义Container最后须要添加到app.stage app.stage.addChild(myContainer); document.body.appendChild(app.view); 复制代码
分组的好处在于,修改container的属性,位于其中的子节点,都会受到影响。好比上面的例子,咱们把rectangle
和rectangle2
分到了同一个组里,若是但愿同时隐藏这两个元素,只需修改它们父级container的透明度便可。
// 父级透明,则子级也透明 myContainer.alpha = 0; 复制代码
一种常见的作法是,咱们建立一个最顶层的rootContainer
,以后全部的内容,都添加到rootContainer
里。而rootContainer
做为顶级元素,能够进行一些缩放来适配不一样的分辨率:
const rootContainer = new Container(); app.stage.addChild(rootContainer); // 相对于设计稿750px进行缩放(竖屏状态) const screenScaleRito = window.innerWidth / 750; // 横屏则用innerHeight rootContainer.scale.set(screenScaleRito, screenScaleRito); 复制代码
这种方法相似咱们前端的rem布局
app.renderer
是一个Renderer
的实例,若是你但愿从新渲染页面,就须要使用它
// 把画布从新渲染为500*500大小 app.renderer.resize(500, 500); // 渲染一个容器 const container = new Container(); app.renderer.render(container); 复制代码
Sprite精灵,你能够把它当作普通的矢量图形,只不过它是根据图片渲染出来的。
const avatar = new Sprite.from('http://anata.me/img/avatar.jpg'); // 和普通的图形同样能够设置各类属性 avatar.width = 100; avatar.height = 200; avatar.position.set(20, 30); avatar.scale.set(2, 2); 复制代码
加载图片一般须要耗费必定的时间,所以咱们经常使用Loader
来预加载图片,当图片所有加载成功后,才渲染出来。
import { Application, Sprite, Loader } from 'pixi.js'; // Loader.shared内置的单例loader const loader = Loader.shared; // 也可使用自定义的loader const loader = new Loader(); const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .add('avatar', 'http://anata.me/img/avatar.jpg') .load(setup) // 监听加载事件 loader.onProgress.add((loader) => { console.log(loader.progress); }); function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; const avatar = new Sprite( loader.resources["avatar"].texture ); avatar.width = 50; avatar.height = 50; avatar.position.set(50, 50); app.stage.addChild(bili); app.stage.addChild(avatar); } 复制代码
经过add
方法添加须要加载的图片,全部图片加载完成后,load
方法会调用传入的setup
回调函数,这时就能够把图片精灵加入到app.stage
里。onProgress
事件能够监听加载的进度,经过这个方法,能够很方便的制做进度条动画。
前端有时会把多张图片合并成一张图片,经过设置background-position
来显示不一样的图片。pixi.js
也有相似的技术,咱们能够利用Texture Packer软件,把多张图片合并成一张图片,合并的同时,软件会生成一份json
配置文件,记录了每张图片的相对位置。
具体教程见这里
import { Application, Container, Sprite, Graphics, Loader, Spritesheet } from 'pixi.js'; // myjson记录了每张图片的相对位置 import myjosn from './assets/treasureHunter.json'; // mypng里面有多张图片 import mypng from './assets/treasureHunter.png'; const loader = Loader.shared; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('mypng', mypng) .load(setup) function setup() { const texture = loader.resources["mypng"].texture.baseTexture; const sheet = new Spritesheet(texture, myjosn); sheet.parse((textures) => { // mypng里面的一张叫treasure.png的图片 const treasure = new Sprite(textures["treasure.png"]); treasure.position.set(0, 0); // mypng里面的一张叫blob.png的图片 const blob = new Sprite(textures["blob.png"]); blob.position.set(100, 100); app.stage.addChild(treasure); app.stage.addChild(blob); }); } 复制代码
Ticker
有点相似前端的requestAnimationFrame
,当浏览器的显示频率刷新的时候,此函数会被执行,所以经常用来制做动画。
app.ticker
就是一个Ticker
实例。
import { Application, Sprite, Loader } from 'pixi.js'; const loader = Loader.shared; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .load(setup) function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; app.stage.addChild(bili); app.ticker.add(() => { if (bili.x <= 200) { bili.x += 1; } }) } 复制代码
咱们也可使用requestAnimationFrame
实现这个效果
function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; app.stage.addChild(bili); function move() { if (bili.x <= 200) { bili.x += 1; requestAnimationFrame(move) } } requestAnimationFrame(move) } 复制代码
Ticker
能够实现简单的动画,但若是咱们但愿实现一些复杂效果,则须要本身编写不少代码,这时就能够选择一个兼容pixi
的动画库。市面上比较常见的动画库有:Tween.js,TweenMax,这里咱们使用TweenMax
来演示效果。
安装动画库
npm i gsap
复制代码
import { Application, Sprite, Loader } from 'pixi.js'; import { TweenMax } from 'gsap/all'; const loader = Loader.shared; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .load(setup) function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; app.stage.addChild(bili); // 1s内x和y轴移动100 TweenMax.to(bili, 1, { x: 100, y: 100 }); } 复制代码
TweenMax
还提供了一个PixiPlugin,能够一次修改多个pixi属性
import { Application, Sprite, Loader } from 'pixi.js'; import * as PIXI from 'pixi.js'; import gsap, { TweenMax, PixiPlugin } from 'gsap/all'; // 注册插件 gsap.registerPlugin(PixiPlugin); PixiPlugin.registerPIXI(PIXI); const loader = Loader.shared; const app = new Application({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); document.body.appendChild(app.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .load(setup) function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; app.stage.addChild(bili); // 一次修改多个属性 TweenMax.to(bili, 1, { pixi: { scaleX: 1.2, scaleY: 1.2, skewX: 10, rotation: 20 } }); } 复制代码
咱们一般使用Pixi提供的Application
方法来建立一个应用,它能自动建立renderer,ticker 和container。但其实,咱们能够本身来建立这些对象。
import { Container, Renderer, Sprite, Loader, Ticker } from 'pixi.js'; import { TweenMax } from 'gsap/all'; // 自定义render const renderer = new Renderer({ width: 300, height: 300, antialias: true, transparent: false, resolution: 1, backgroundColor: 0x1d9ce0 }); // 自定义container const stage = new Container(); // 自定义loader const loader = new Loader(); // 自定义ticker const ticker = new Ticker(); // 每次屏幕刷新从新渲染,不然只会渲染第一帧 ticker.add(() => { renderer.render(stage); }); // 开始执行ticker,必定要调用这个方法,注册的回调函数才会被执行!!! ticker.start(); document.body.appendChild(renderer.view); loader .add('bili', 'http://pic.deepred5.com/bilibili.jpg') .load(setup) function setup() { const bili = new Sprite( loader.resources["bili"].texture ); bili.width = 50; bili.height = 50; stage.addChild(bili); // 动画效果 ticker.add(() => { if (bili.x <= 200) { bili.x += 2; } }); TweenMax.to(bili, 1, { y: 100, delay: 3 }); } 复制代码
其实PIXI.Application的底层就是帮咱们简化了上述的操做。