Игровая платформа PixiJS: полный обзор
PixiJS – это быстрая и легкая библиотека 2D-рендеринга, которая создает красивый цифровой контент с помощью самого быстрого и гибкого 2D-рендерера WebGL. Она предоставляет простой API и использует аппаратное ускорение для достижения оптимальной производительности.
Основные характеристики PixiJS:
- WebGL First: Аппаратно-ускоренный рендеринг с резервной версией Canvas
- Кроссплатформенный: Работает в Интернете, на мобильных устройствах и на настольных компьютерах
- Scene Graph: Иерархическая объектная модель отображения
- Архитектура плагинов: Расширяемая с помощью официальных плагинов и плагинов сообщества
- Поддержка TypeScript: Включены полные определения типов
Базовая архитектура
Setup приложения
import { Application } from 'pixi.js';
// Create application
const app = new Application({
width: 800,
height: 600,
backgroundColor: 0x1099bb,
resolution: window.devicePixelRatio || 1,
antialias: true
});
// Add to DOM
document.body.appendChild(app.view);
Иерархия отображаемых объектов
// Container - base display object
const container = new Container();
// Sprite - bitmap images
const sprite = new Sprite(texture);
// Graphics - vector shapes
const graphics = new Graphics();
// Text - rendered text
const text = new Text('Hello World');
// Scene graph structure
app.stage.addChild(container);
container.addChild(sprite);
container.addChild(graphics);
Графика и рендеринг
Векторная графика
const graphics = new Graphics();
// Basic shapes
graphics.beginFill(0xFF3300);
graphics.drawRect(50, 50, 100, 100);
graphics.endFill();
// Complex paths
graphics.lineStyle(2, 0xFFFFFF, 1);
graphics.moveTo(50, 50);
graphics.lineTo(100, 100);
graphics.bezierCurveTo(100, 50, 200, 50, 200, 100);
// Circles and arcs
graphics.beginFill(0x00FF00);
graphics.drawCircle(100, 100, 50);
graphics.arc(200, 200, 50, 0, Math.PI);
Расширенные графические возможности
// Gradients
const gradient = new FillGradient(0, 0, 0, 100);
gradient.addColorStop(0, 0xFF0000);
gradient.addColorStop(1, 0x0000FF);
graphics.beginFill(gradient);
// Masks
const mask = new Graphics();
mask.beginFill(0xFFFFFF);
mask.drawCircle(100, 100, 50);
sprite.mask = mask;
// Blend modes
sprite.blendMode = BLEND_MODES.ADD;
Спрайты и текстуры
Управление текстурами
import { Texture, Sprite, Assets } from 'pixi.js';
// Load textures
await Assets.load('sprite.png');
const texture = Assets.get('sprite.png');
// Create sprite
const sprite = new Sprite(texture);
sprite.anchor.set(0.5); // Center anchor
sprite.position.set(400, 300);
sprite.scale.set(2, 2);
sprite.rotation = Math.PI / 4;
Списки и атласы спрайтов
// Load sprite sheet
await Assets.load('spritesheet.json');
const sheet = Assets.get('spritesheet.json');
// Create sprite from atlas
const sprite = new Sprite(sheet.textures['frame1.png']);
// Animated sprite
const textures = [];
for (let i = 0; i < 30; i++) {
textures.push(sheet.textures[`frame${i}.png`]);
}
const animatedSprite = new AnimatedSprite(textures);
animatedSprite.animationSpeed = 0.1;
animatedSprite.play();
Генерация текстур
// Create texture from canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// ... draw on canvas
const texture = Texture.from(canvas);
// Render texture for dynamic content
const renderTexture = RenderTexture.create({
width: 200,
height: 200
});
app.renderer.render(graphics, { renderTexture });
Анимация и настройка параметров
Анимация на основе бегущей строки
// Game loop
app.ticker.add((delta) => {
sprite.rotation += 0.01 * delta;
sprite.position.x += 1 * delta;
});
// Custom ticker
const ticker = new Ticker();
ticker.add(updateFunction);
ticker.start();
Tween Libraries Integration
// With gsap
import { gsap } from 'gsap';
gsap.to(sprite, {
duration: 2,
x: 400,
y: 300,
rotation: Math.PI * 2,
ease: "bounce.out"
});
// Custom easing
function animate() {
requestAnimationFrame(animate);
sprite.x += (targetX - sprite.x) * 0.1;
sprite.y += (targetY - sprite.y) * 0.1;
}
Взаимодействие и события
События, связанные с мышью/касанием
// Enable interaction
sprite.interactive = true;
sprite.buttonMode = true;
// Event listeners
sprite.on('pointerdown', onDragStart);
sprite.on('pointerup', onDragEnd);
sprite.on('pointermove', onDragMove);
sprite.on('pointerover', onHover);
function onDragStart(event) {
this.alpha = 0.5;
this.dragging = true;
this.data = event.data;
}
function onDragMove() {
if (this.dragging) {
const newPosition = this.data.getLocalPosition(this.parent);
this.x = newPosition.x;
this.y = newPosition.y;
}
}
Проверка столкновения
// Custom hit areas
const hitArea = new Rectangle(0, 0, 100, 50);
sprite.hitArea = hitArea;
// Polygon hit areas
const polygon = new Polygon([0, 0, 100, 0, 50, 100]);
sprite.hitArea = polygon;
// Manual hit testing
const globalPoint = new Point(mouseX, mouseY);
const localPoint = sprite.toLocal(globalPoint);
const hit = sprite.containsPoint(localPoint);
Фильтры и эффекты
Встроенные фильтры
import { BlurFilter, ColorMatrixFilter, DisplacementFilter } from 'pixi.js';
// Blur filter
const blurFilter = new BlurFilter();
blurFilter.blur = 2;
sprite.filters = [blurFilter];
// Color effects
const colorMatrix = new ColorMatrixFilter();
colorMatrix.sepia();
colorMatrix.contrast(1.2);
// Displacement mapping
const displacementSprite = new Sprite(noiseTexture);
const displacementFilter = new DisplacementFilter(displacementSprite);
displacementFilter.scale.x = 30;
displacementFilter.scale.y = 60;
Кастомные фильтры
// Custom fragment shader
const fragmentShader = `
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform float time;
void main(void) {
vec2 coord = vTextureCoord;
coord.x += sin(coord.y * 10.0 + time) * 0.01;
gl_FragColor = texture2D(uSampler, coord);
}
`;
class WaveFilter extends Filter {
constructor() {
super(null, fragmentShader, {
time: 0
});
}
get time() {
return this.uniforms.time;
}
set time(value) {
this.uniforms.time = value;
}
}
Рендеринг текста
Базовый текст
const style = new TextStyle({
fontFamily: 'Arial',
fontSize: 36,
fontStyle: 'italic',
fontWeight: 'bold',
fill: ['#ffffff', '#00ff99'], // gradient
stroke: '#4a1850',
strokeThickness: 5,
dropShadow: true,
dropShadowColor: '#000000',
dropShadowBlur: 4,
dropShadowAngle: Math.PI / 6,
dropShadowDistance: 6,
wordWrap: true,
wordWrapWidth: 440
});
const text = new Text('This is a PixiJS text', style);
Растровые шрифты
// Load bitmap font
await Assets.load('desyrel.xml');
// Create bitmap text
const bitmapText = new BitmapText('bitmap fonts are supported', {
fontName: 'Desyrel',
fontSize: 55,
align: 'left'
});
Оптимизация производительности
Пулинг (pooling) объектов
class BulletPool {
constructor() {
this.bullets = [];
this.active = [];
}
get() {
let bullet = this.bullets.pop();
if (!bullet) {
bullet = new Sprite(bulletTexture);
}
this.active.push(bullet);
return bullet;
}
release(bullet) {
const index = this.active.indexOf(bullet);
if (index > -1) {
this.active.splice(index, 1);
this.bullets.push(bullet);
bullet.parent?.removeChild(bullet);
}
}
}
Выбраковка объектов и оптимизация
// Frustum culling
function cullObjects(container, bounds) {
for (let child of container.children) {
const childBounds = child.getBounds();
child.visible = bounds.intersects(childBounds);
if (child.children) {
cullObjects(child, bounds);
}
}
}
// Batch rendering optimization
const particleContainer = new ParticleContainer(10000, {
scale: true,
position: true,
rotation: true,
uvs: true,
alpha: true
});
Управление памятью
// Proper cleanup
function cleanup() {
// Remove from stage
app.stage.removeChild(sprite);
// Destroy sprite and texture
sprite.destroy({
children: true,
texture: true,
baseTexture: true
});
// Clear references
sprite = null;
}
Продвинутые возможности
Graphics API 2.0
// Proper cleanup
function cleanup() {
// Remove from stage
app.stage.removeChild(sprite);
// Destroy sprite and texture
sprite.destroy({
children: true,
texture: true,
baseTexture: true
});
// Clear references
sprite = null;
}
Рендеринг сетки
// Custom geometry
const geometry = new Geometry()
.addAttribute('aVertexPosition', vertices, 2)
.addAttribute('aTextureCoord', uvs, 2)
.addIndex(indices);
const shader = Shader.from(vertexShader, fragmentShader);
const mesh = new Mesh(geometry, shader);
Экосистема плагинов
Официальные плагины
// Sound plugin
import { sound } from '@pixi/sound';
sound.add('explosion', 'explosion.mp3');
sound.play('explosion');
// Spine animations
import { Spine } from 'pixi-spine';
const animation = new Spine(spineData);
// Particle systems
import { Emitter } from '@pixi/particle-emitter';
const emitter = new Emitter(container, particleConfig);
Integration Examples
// Physics with Matter.js
import { Engine, World, Bodies } from ‘matter-js’;
const engine = Engine.create();
const world = engine.world;
// Create physics body
const body = Bodies.rectangle(400, 200, 80, 80);
World.add(world, body);
Кейсы и приложения
Разработка игр
- 2D-игры со сложной графикой
- Игровые движки HTML5
- Интерактивный образовательный контент
- Визуализация данных
- Цифровые художественные инсталляции
Вопросы производительности
- Стратегии оптимизации для мобильных устройств
- Создание атласов текстур для уменьшения количества розыгрышей
- Системы с уровнем детализации (LOD)
- Эффективные системы частиц
- Загрузка ресурсов с учетом памяти
Сравнение PixiJS с конкурентами
Сравнение PixiJS с конкурентами можно посмотреть здесь ==>>
PixiJS преуспевает в создании высокопроизводительных приложений для 2D-графики благодаря мощному движку рендеринга, широкому набору функций и превосходному опыту разработчиков, сохраняя при этом кроссплатформенную совместимость и расширяемость благодаря богатой экосистеме плагинов.