|

Игровая платформа 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-графики благодаря мощному движку рендеринга, широкому набору функций и превосходному опыту разработчиков, сохраняя при этом кроссплатформенную совместимость и расширяемость благодаря богатой экосистеме плагинов.

Также может быть интересно: