О чем этот пример

Работа с двумерными массивами (матрицами) — частая задача в игровой разработке, будь то генерация уровней, карты тайлов или логические головоломки. Встроенные утилиты Phaser упрощают манипуляции с такими структурами данных. В этой статье мы разберем пример использования `Phaser.Utils.Array.Matrix.Translate()` для сдвига матрицы в любом направлении. Вы научитесь динамически изменять игровые данные по клику, что открывает возможности для создания интерактивных редакторов и механик, основанных на перемещении блоков данных.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('arrow', 'assets/sprites/arrow.png');
    }

    create ()
    {
        this.add.text(10, 10, 'Click to arrows to translate the array matrix', { font: '16px Courier', fill: '#ffffff' });

        const left = this.add.image(96, 384, 'arrow').setAngle(-180).setInteractive();
        const right = this.add.image(1024 - 96, 384, 'arrow').setInteractive();
        const up = this.add.image(512, 96, 'arrow').setAngle(-90).setInteractive();
        const down = this.add.image(512, 768 - 96, 'arrow').setAngle(90).setInteractive();

        const text = this.add.text(260, 200, '', { font: '32px Courier', fill: '#00ff00' });

        let matrix = [
            [ 1, 1, 1, 1, 1, 1, 1 ],
            [ 4, 5, 5, 5, 5, 5, 2 ],
            [ 4, 8, 8, 8, 8, 6, 2 ],
            [ 4, 8, 9, 0, 9, 6, 2 ],
            [ 4, 8, 9, 9, 9, 6, 2 ],
            [ 4, 7, 7, 7, 7, 7, 2 ],
            [ 3, 3, 3, 3, 3, 3, 3 ]
        ];

        text.setText(Phaser.Utils.Array.Matrix.MatrixToString(matrix));

        left.on('pointerup', () =>
        {

            matrix = Phaser.Utils.Array.Matrix.Translate(matrix, -1, 0);

            text.setText(Phaser.Utils.Array.Matrix.MatrixToString(matrix));

        });

        right.on('pointerup', () =>
        {

            matrix = Phaser.Utils.Array.Matrix.Translate(matrix, 1, 0);

            text.setText(Phaser.Utils.Array.Matrix.MatrixToString(matrix));

        });

        up.on('pointerup', () =>
        {

            matrix = Phaser.Utils.Array.Matrix.Translate(matrix, 0, -1);

            text.setText(Phaser.Utils.Array.Matrix.MatrixToString(matrix));

        });

        down.on('pointerup', () =>
        {

            matrix = Phaser.Utils.Array.Matrix.Translate(matrix, 0, 1);

            text.setText(Phaser.Utils.Array.Matrix.MatrixToString(matrix));

        });
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Подготовка сцены и элементов управления

Класс Example расширяет Phaser.Scene. В методе preload загружается спрайт стрелки. В create создаются четыре интерактивных изображения стрелок, повернутых в разные стороны, которые будут служить кнопками управления.

Также создается текстовый объект text для отображения матрицы и инициализируется сама матрица matrix — двумерный массив чисел. Для удобного отображения используется функция Phaser.Utils.Array.Matrix.MatrixToString().

const left = this.add.image(96, 384, 'arrow').setAngle(-180).setInteractive();
const right = this.add.image(1024 - 96, 384, 'arrow').setInteractive();
const up = this.add.image(512, 96, 'arrow').setAngle(-90).setInteractive();
const down = this.add.image(512, 768 - 96, 'arrow').setAngle(90).setInteractive();

const text = this.add.text(260, 200, '', { font: '32px Courier', fill: '#00ff00' });

let matrix = [
    [ 1, 1, 1, 1, 1, 1, 1 ],
    [ 4, 5, 5, 5, 5, 5, 2 ],
    [ 4, 8, 8, 8, 8, 6, 2 ],
    [ 4, 8, 9, 0, 9, 6, 2 ],
    [ 4, 8, 9, 9, 9, 6, 2 ],
    [ 4, 7, 7, 7, 7, 7, 2 ],
    [ 3, 3, 3, 3, 3, 3, 3 ]
];

text.setText(Phaser.Utils.Array.Matrix.MatrixToString(matrix));

Связывание событий с функцией Translate

Каждой стрелке назначается обработчик события 'pointerup'. Внутри обработчика вызывается ключевая функция Phaser.Utils.Array.Matrix.Translate(). Она принимает три аргумента: 1. Исходную матрицу. 2. Смещение по горизонтали (`x`). 3. Смещение по вертикали (`y`).

Функция возвращает **новую матрицу**, сдвинутую на указанное количество строк и столбцов. Элементы, выходящие за границы, "заворачиваются" с противоположной стороны (циклический сдвиг). Результат присваивается переменной matrix, а затем обновляется текст на экране.

left.on('pointerup', () => {
    matrix = Phaser.Utils.Array.Matrix.Translate(matrix, -1, 0);
    text.setText(Phaser.Utils.Array.Matrix.MatrixToString(matrix));
});

right.on('pointerup', () => {
    matrix = Phaser.Utils.Array.Matrix.Translate(matrix, 1, 0);
    text.setText(Phaser.Utils.Array.Matrix.MatrixToString(matrix));
});

Как работает Translate и его параметры

Функция Translate выполняет циклический сдвиг (rotation) матрицы. Это значит, что строки или столбцы, которые "выталкиваются" за пределы массива, не теряются, а появляются с другой стороны.

* Translate(matrix, 1, 0) сдвигает все столбцы вправо. Крайний правый столбец становится крайним левым. * Translate(matrix, -1, 0) сдвигает все столбцы влево. * Translate(matrix, 0, 1) сдвигает все строки вниз. Нижняя строка становится верхней. * Translate(matrix, 0, -1) сдвигает все строки вверх.

Можно задавать смещение больше единицы: Translate(matrix, 2, -1) сдвинет матрицу на два столбца вправо и на одну строку вверх.

Важно понимать, что исходная матрица **не изменяется**. Функция всегда возвращает новый массив.

Практическое применение в играх

Эта техника полезна не только для отображения чисел. Представьте, что значения в матрице — это ID тайлов на карте уровня. Тогда Translate позволит реализовать:

* **Бесконечно прокручиваемую карту** (как в старых пошаговых стратегиях). * **Механику сдвигающих платформ или блоков** в головоломках (например, как в игре "Пятнашки"). * **Простой редактор уровней**, где вы можете "прокручивать" заготовленный фрагмент карты. * **Генерацию ландшафта** на лету, смещая и дополняя матрицу с данными.

Вместо чисел в матрице могут храниться объекты, описывающие состояние клетки игрового поля.

Что попробовать дальше

Утилита Phaser.Utils.Array.Matrix.Translate() — мощный и простой инструмент для работы с двумерными данными. Она избавляет от необходимости писать вложенные циклы для ручного сдвига массивов. Для экспериментов попробуйте: 1. Связать матрицу с сеткой спрайтов на сцене, чтобы визуализировать сдвиг графически. 2. Использовать не циклический сдвиг, а добавлять новые строки/столбцы с дефолтными значениями при выходе за границы. 3. Комбинировать Translate с другими функциями из Phaser.Utils.Array.Matrix, например, RotateMatrix для поворота данных.