--- title: "🧰 Pixi.js: Пример эффекта параллакс и использование ассетов" date: 2022-10-29T00:24:59+03:00 draft: false tags: [pixijs, gamedev, tutorial, javascript] --- ## Pixi.js 7.0.0 4 часа назад вышла [7–я версия](https://github.com/pixijs/pixijs/releases/tag/v7.0.0) библиотеки [Pixi.js](https://pixijs.com). Для тех, кто уже использует Pixi.js подготовлен [документ](https://github.com/pixijs/pixijs/wiki/v7-Migration-Guide) по миграции на новую версию. В данном примере будем использовать загрузчик ассетов [PIXI.Assets](https://pixijs.download/release/docs/PIXI.Assets.html), который потеснил [PIXI.Loader](https://pixijs.download/release/docs/PIXI.Loader.html). Подробнее написано здесь: [v7-Migration-Guide#-replaces-loader-with-assets](https://github.com/pixijs/pixijs/wiki/v7-Migration-Guide#-replaces-loader-with-assets). ## PIXI.Assets > PIXI.Assets — это универсальный инструмент для управления ресурсами в Pixi! > Суперсовременный и простой в использовании, с достаточной гибкостью, > чтобы настраивать и делать то, что вам нужно! ### Загрузка ассетов Не бойся загружать данные несколько раз — Pixi.Assets **НИКОГДА** ничего не загрузит больше одного раза. Например: ```javascript promise1 = PIXI.Assets.load('bunny.png') promise2 = PIXI.Assets.load('bunny.png') // promise1 === promise2 ``` Вот несколько примеров загрузки ассетов: ```javascript // простой пример PIXI.Assets.add('bunnyBooBoo', 'bunny.png'); const bunny = await PIXI.Assets.load('bunnyBooBoo'); // несколько значений PIXI.Assets.add(['burger', 'chicken'], 'bunny.png'); const bunny = await PIXI.Assets.load('burger'); const bunny2 = await PIXI.Assets.load('chicken'); // передача параметров объекту PIXI.Assets.add( 'bunnyBooBooSmooth', 'bunny{png,webp}', {scaleMode:SCALE_MODES.NEAREST}, ); ``` ## Каркас приложения HTML документ `index.html`: ```html pixi.js - assets & parallax ``` Код приложения `app.js` ```javascript let app; let backgroundTextures; let background = { sky: null, back: null, middle: null, front: null, x: 0, speed: 1, }; /** Инициализация PIXI и настройка PIXI.Assets */ window.onload = function() { app = new PIXI.Application({ width: 640, height: 360, backgroundColor: 0x2a2a3a, }); document.body.appendChild(app.view); } /** Функция инициализации уровня */ function initLevel() { app.ticker.add(gameLoop); } /** Игровой цикл */ function gameLoop(delta) { // } ``` В переменной `app` я буду хранить объект `PIXI.Application`, чтобы можно было получать доступ к нему из других функций. В переменную `backgroundTextures` будет загружать текстуры. Переменная `background` отвечает за необходимые параметры, такие как скорость эффекта параллакса и положение тайлов изображений **sky**, **back**, **middle**, **front**. В этом примере я буду использовать ассет [Desert Parallax Background](https://styloo.itch.io/desert-parallax-background) за авторством **styloo**. В этом ассете есть фон, и три изображения с частями пустыни. ## Добавление ассетов Я распаковал ассет **Desert Parallax Background** в директорию `assets`, а также переименовал изображения. Теперь в функцию `window.onload = function() {}` указываем ресурсы, которые я буду загружать и вызываем их загрузку. ```javascript PIXI.Assets.add('bg_back', '/assets/3.png'); PIXI.Assets.add('desert_2', '/assets/2.png'); PIXI.Assets.add('desert_1', '/assets/1.png'); PIXI.Assets.add('desert_0', '/assets/0.png'); let promise = PIXI.Assets.load( ['bg_back', 'desert_2', 'desert_1', 'desert_0'], (progress) => { console.log(`Assets loading progress: ${progress * 100}%`); }); ``` Функция `PIXI.Assets.load` принимает в качестве аргумента имя ассета, который необходимо загрузить, либо список ассетов. Второй необязательный аргумент, это callback функция, которая вызывается во время загрузки Ассетов. Функции передается параметр `progress`, который представляет процент (0.0 - 1.0) загруженных ассетов. Функция возвращает **Promise** ассетов, которые были загружены. По окончании загрузки ассетов, я вызываю функцию `initLevel()`, а также передаю в переменную `backgroundTextures` список загруженых ассетов, в данном случае это текстуры. ```javascript promise.then((value) => { backgroundTextures = value; initLevel(); }); ``` ## Инициализация тайлов Для создания тайлов, я написал функцию `createBg()`, которая создаёт объект [PIXI.TilingSprite](https://pixijs.download/release/docs/PIXI.TilingSprite.html) и устанавливает позицию на экране. ```javascript function createBg(texture) { let tiling = new PIXI.TilingSprite(texture, 640, 360); tiling.position.set(0, 0); app.stage.addChild(tiling); return tiling; } ``` Создаёт тайлы: ```javascript function initLevel() { background.sky = createBg(backgroundTextures.bg_back); background.back = createBg(backgroundTextures.desert_2); background.middle = createBg(backgroundTextures.desert_1); background.front = createBg(backgroundTextures.desert_0); app.ticker.add(gameLoop); } ``` ## Создаём эффект параллакса Этот этап самый простой. В игровом цикле я изменяю значение переменной `background.x` и смещаю позицию тайлов. ```javascript function gameLoop(delta) { background.x = (background.x - background.speed); background.front.tilePosition.x = background.x; background.middle.tilePosition.x = background.x / 2; background.back.tilePosition.x = background.x / 4; } ``` ## Исходный код ```javascript const DEBUG = true; let app; let backgroundTextures; let background = { sky: null, back: null, middle: null, front: null, x: 0, speed: 1, }; /** PIXI and PIXI.Assets init */ window.onload = function() { app = new PIXI.Application({ width: 640, height: 360, backgroundColor: 0x2a2a3a, }); document.body.appendChild(app.view); PIXI.Assets.add('bg_back', '/assets/3.png'); PIXI.Assets.add('desert_2', '/assets/2.png'); PIXI.Assets.add('desert_1', '/assets/1.png'); PIXI.Assets.add('desert_0', '/assets/0.png'); let promise = PIXI.Assets.load( ['bg_back', 'desert_2', 'desert_1', 'desert_0'], (progress) => { if (DEBUG) console.log(`Assets loading progress: ${progress * 100}%`); }); promise.then((value) => { backgroundTextures = value; initLevel(); }); } /** Level init */ function initLevel() { background.sky = createBg(backgroundTextures.bg_back); background.back = createBg(backgroundTextures.desert_2); background.middle = createBg(backgroundTextures.desert_1); background.front = createBg(backgroundTextures.desert_0); app.ticker.add(gameLoop); } /** Game loop */ function gameLoop(delta) { background.x = (background.x - background.speed); background.front.tilePosition.x = background.x; background.middle.tilePosition.x = background.x / 2; background.back.tilePosition.x = background.x / 4; } /** Create background sprite */ function createBg(texture) { let tiling = new PIXI.TilingSprite(texture, 640, 360); tiling.position.set(0, 0); app.stage.addChild(tiling); return tiling; } ```