О чем этот пример
При разработке игр часто возникает задача генерации комбинаций элементов: уровней, врагов, диалогов или анимационных ключей. Писать вложенные циклы каждый раз неэффективно. Утилита `Phaser.Utils.Array.Range` из библиотеки Phaser 3 решает эту проблему, предлагая гибкий инструмент для создания последовательностей на основе двух массивов. Эта статья покажет, как с её помощью генерировать предсказуемые и случайные комбинации, управлять количеством и порядком элементов, что полезно при создании процедурного контента, систем волн противников или сложных цепочек событий.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
create ()
{
// var a = [ 'a', 'b', 'c' ];
// var a = [ 'a' ];
const a = [ 'a', 'b' ];
const b = [ 1, 2 ];
// var b = [ 1, 2, 3 ];
// var b = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
// var out = Phaser.Utils.Array.Range(a, b);
// var out = Phaser.Utils.Array.Range(a, b, { repeat: 1 });
// var out = Phaser.Utils.Array.Range(a, b, { yoyo: true, repeat: 1 });
// var out = Phaser.Utils.Array.Range(a, b, { qty: 3, yoyo: true });
// var out = Phaser.Utils.Array.Range(a, b, { random: true });
// var out = Phaser.Utils.Array.Range(a, b, { randomB: true });
const out = Phaser.Utils.Array.Range(a, b, { repeat: -1, max: 10 });
const text = [ '{' ];
out.forEach(e =>
{
text.push(` ${JSON.stringify(e)}`);
});
text.push('}');
this.add.text(100, 100, text, { font: '32px Courier', fill: '#00ff00' });
}
}
const config = {
type: Phaser.CANVAS,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что делает Phaser.Utils.Array.Range?
Метод Phaser.Utils.Array.Range генерирует новый массив, комбинируя элементы из двух исходных массивов (`aиb`) согласно заданным правилам. Базовый принцип похож на декартово произведение: каждый элемент первого массива последовательно сопоставляется с каждым элементом второго, формируя пары. Однако утилита предлагает гораздо больше контроля над процессом через объект настроек.
Рассмотрим сигнатуру метода:
Phaser.Utils.Array.Range(a, b, options)
Здесь `aиb— исходные массивы любого типа.options` — необязательный объект конфигурации, который мы детально разберем в следующих разделах.
Базовое использование и настройка повторений
Без передачи объекта options метод создаст простую последовательность пар, перебирая все элементы массива `bдля каждого элемента массиваa`.
const letters = ['a', 'b'];
const numbers = [1, 2];
const out = Phaser.Utils.Array.Range(letters, numbers);
// Результат: [ ['a',1], ['a',2], ['b',1], ['b',2] ]
Ключ repeat позволяет повторить всю сгенерированную последовательность указанное количество раз. Значение -1 задает бесконечное повторение, которое ограничивается ключом max.
const out = Phaser.Utils.Array.Range(a, b, { repeat: 1 });
// Последовательность пройдет дважды.
const out = Phaser.Utils.Array.Range(a, b, { repeat: -1, max: 10 });
// Бесконечное повторение, но всего будет сгенерировано 10 элементов.
Использование эффекта йо-йо и ограничение количества
Опция yoyo изменяет поведение при повторении. Если yoyo: true, то при каждом новом проходе последовательность будет воспроизводиться в обратном порядке, создавая эффект "туда-обратно".
const out = Phaser.Utils.Array.Range(a, b, { yoyo: true, repeat: 1 });
// Прямой проход: [a,1], [a,2], [b,1], [b,2]
// Обратный проход (йо-йо): [b,2], [b,1], [a,2], [a,1]
Ключ qty позволяет явно задать общее количество элементов в итоговом массиве. Метод самостоятельно рассчитает, сколько полных или частичных циклов нужно сделать для достижения этого числа.
const out = Phaser.Utils.Array.Range(a, b, { qty: 3, yoyo: true });
// Будет создан массив ровно из 3 пар, с учетом йо-йо.
Генерация случайных последовательностей
Утилита предоставляет два способа внести случайность в результат. Опция random: true перемешивает весь итоговый массив после его генерации по стандартным правилам.
const out = Phaser.Utils.Array.Range(a, b, { random: true });
// Пары будут следовать в случайном порядке.
Более интересна опция randomB: true. В этом случае для каждого элемента из массива `aбудет выбран *случайный* элемент из массиваb`. Это не просто перемешивание, а случайное сопоставление на этапе создания пар.
const out = Phaser.Utils.Array.Range(a, b, { randomB: true });
// Для 'a' случайно выбран элемент из [1,2], для 'b' — другой случайный элемент из [1,2].
Практическое применение в играх
Рассмотрим несколько идей, где Phaser.Utils.Array.Range сэкономит время и строки кода.
**Генерация волн противников:**
const enemyTypes = ['grunt', 'ranged', 'tank'];
const spawnPoints = [100, 200, 300, 400];
const wave = Phaser.Utils.Array.Range(enemyTypes, spawnPoints, { random: true, max: 15 });
// Создаст 15 пар [тип врага, точка появления] в случайном порядке.
**Создание сетки анимационных ключей для спрайта:**
const actions = ['idle', 'walk', 'attack'];
const directions = ['north', 'east', 'south', 'west'];
const animationKeys = Phaser.Utils.Array.Range(actions, directions);
// Получим массив вида ['idle_north', 'idle_east', ..., 'attack_west'] для загрузки атласа.
**Построение диалоговых цепочек с йо-йо:**
const characters = ['hero', 'npc'];
const moods = ['neutral', 'angry', 'happy'];
const dialogueSequence = Phaser.Utils.Array.Range(characters, moods, { yoyo: true, repeat: 2 });
// Диалог будет плавно переходить от нейтральных реплик к эмоциональным и обратно.
Что попробовать дальше
Phaser.Utils.Array.Range — мощный и недооцененный инструмент для декларативного описания последовательностей. Он убирает из кода шаблонные вложенные циклы и сложную логику индексов, делая его чище и нагляднее. Для экспериментов попробуйте комбинировать опции: создайте бесконечную йо-йо последовательность (repeat: -1, yoyo: true) с ограничением по max для плавного патрулирования врага или используйте randomB для генерации уровней, где каждая комната содержит случайный, но связанный с типом комнаты набор предметов.
