PixiJSЭто облегченный механизм 2D-рендеринга, который автоматически определяет, следует ли использовать WebGL или Canvas для создания графики. Эта библиотека часто используется для создания игр HTML5 и страниц активности H5 со сложными взаимодействиями.
среда сборки
Примечание. В этой статье используется последняя версия pixi v5, при этом используетсяParcelмодульная упаковка
pixi.js
Версия v5 по умолчанию использует рендеринг webgl.Если вы хотите вернуться к холсту, вам нужно использоватьpixi.js-legacy
, видетьissue
Инициализация проекта
mkdir learn-pixi
cd learn-pixi
npm init -y
Установить зависимости
npm i pixi.js -save
npm i parcel-bundler -save-dev
создание корневого каталогаindex.html
<!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
alert('pixi');
Исправлятьpackage.json
"scripts": {
"dev": "parcel index.html -p 8080",
"build": "parcel build index.html"
}
бегатьnpm run dev
,доступhttp://localhost:8080/увидеть эффект
быстрый старт
index.js
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.
Мы можем продолжать создавать новую графику и отображать ее на холсте.
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
Есть несколько важных классов:
- Контейнер (сцена, сцена)
- Рендерер
- Тикер (таймер)
- Загрузчик (загрузчик ресурсов)
- Спрайт
const app = new Application({
width: 300,
height: 300
});
Application
Это инструментальный метод, предоставляемый pixi, который может автоматически создавать визуализатор, тикер и контейнер.Мы обычно используем этот метод для быстрого создания приложений.
Container
app.stage
ЯвляетсяContainer
Экземпляр , как самая нижняя стадия, внутри которой должна быть размещена вся визуализируемая графика.
const app = new Application({
width: 300,
height: 300
});
// 添加不同的图形
app.stage.addChild(circle1);
app.stage.addChild(circle2);
Мы также можем создать свой собственный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);
Преимущество группировки в том, что при изменении свойств контейнера будут затронуты расположенные в нем дочерние узлы. Например, в приведенном выше примере мы имеемrectangle
а такжеrectangle2
Они назначены одной и той же группе. Если вы хотите скрыть эти два элемента одновременно, вам нужно только изменить прозрачность своего родительского контейнера.
// 父级透明,则子级也透明
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 нашего внешнего интерфейса.
Renderer
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
Чтобы предварительно загрузить изображение, когда все изображение успешно загружено, оно будет отображено.
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
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
метод для создания приложения, которое автоматически создает средства визуализации, бегущие строки и контейнеры. Но на самом деле мы можем создавать эти объекты сами.
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Нижний слой поможет нам упростить вышеуказанные операции.