Blog/content/posts/pixijs/assets-and-parallax.md

287 lines
9.0 KiB
Markdown
Raw Normal View History

2022-10-29 01:05:47 +03:00
---
2022-11-19 03:36:06 +03:00
title: "🧰 Pixi.js: Пример эффекта параллакс и использование ассетов"
2022-10-29 01:05:47 +03:00
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>pixi.js - assets &amp; parallax</title>
<script type="text/javascript" src="pixi.js"></script>
</head>
<body>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
```
Код приложения `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;
}
```