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

В игровом движке Phaser обновление позиции спрайтов — одна из самых частых задач. В этой статье мы разберем, как правильно использовать метод `update()` для создания плавной анимации движения. Вы научитесь управлять координатами изображений и спрайтов из атласа, реализуете простой механизм «телепортации» при достижении границы экрана и поймете базовый принцип игрового цикла на практике.

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

Живой запуск

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

Исходный код


var config = {
    type: Phaser.CANVAS,
    parent: 'phaser-example',
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

var game = new Phaser.Game(config);

var atlasFrame;
var singleImage;

function preload() {

    
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('atari', 'assets/sprites/atari130xe.png');
    this.load.atlas('atlas', 'assets/atlas/megaset-0.png', 'assets/atlas/megaset-0.json');

}

function create() {

    atlasFrame = this.add.image(0, 0, 'atlas', 'dragonwiz');
    singleImage = this.add.image(200, 0, 'atari');

}

function update() {

    singleImage.x += 4;

    if (singleImage.x > this.game.config.width)
    {
        singleImage.x = 0;
        singleImage.y += 64;
    }

    atlasFrame.x += 4;

    if (atlasFrame.x > this.game.config.width)
    {
        atlasFrame.x = 0;
        atlasFrame.y += 64;
    }

}

Загрузка ресурсов в preload()

Перед созданием любых игровых объектов необходимо загрузить их графические ресурсы. В примере загружаются два типа ресурсов: отдельное изображение и атлас спрайтов.

function preload() {
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('atari', 'assets/sprites/atari130xe.png');
    this.load.atlas('atlas', 'assets/atlas/megaset-0.png', 'assets/atlas/megaset-0.json');
}

Метод this.load.image() загружает одно изображение и присваивает ему ключ 'atari'. Метод this.load.atlas() загружает атлас — изображение, содержащее множество спрайтов, и JSON-файл с координатами кадров внутри него. Ключ 'atlas' будет использоваться для доступа ко всему атласу, а конкретный кадр выбирается по имени, например 'dragonwiz'.

Создание объектов в create()

После загрузки ресурсов в методе create() создаются игровые объекты — экземпляры класса Image. Они помещаются на сцену с заданными начальными координатами.

function create() {
    atlasFrame = this.add.image(0, 0, 'atlas', 'dragonwiz');
    singleImage = this.add.image(200, 0, 'atari');
}

Первый объект atlasFrame создается из атласа. Параметры метода this.add.image(): X=0, Y=0, ключ атласа 'atlas', имя кадра 'dragonwiz'. Второй объект singleImage создается из отдельного изображения с ключом 'atari' и смещен по оси X на 200 пикселей. Оба объекта размещаются в верхней части экрана, так как их координата Y равна 0.

Обновление позиций в update()

Метод update() вызывается на каждом кадре игры. Здесь происходит изменение состояния игровых объектов — в данном случае, их позиции.

function update() {
    singleImage.x += 4;
    if (singleImage.x > this.game.config.width) {
        singleImage.x = 0;
        singleImage.y += 64;
    }

    atlasFrame.x += 4;
    if (atlasFrame.x > this.game.config.width) {
        atlasFrame.x = 0;
        atlasFrame.y += 64;
    }
}

Каждый кадр координата X обоих объектов увеличивается на 4 пикселя, создавая иллюзию движения вправо. Условие if (singleImage.x > this.game.config.width) проверяет, вышел ли объект за правую границу экрана. Ширина экрана берется из конфигурации игры this.game.config.width. Если объект вышел за границу, его X сбрасывается в 0 (левая граница), а Y увеличивается на 64 пикселя, опуская объект на строку ниже. Это создает эффект «переноса» объекта на новую строку, подобно тексту на печатной машинке.

Ключевые моменты работы с координатами

Прямое изменение свойств .x и .y — самый простой способ перемещения объектов типа Image или Sprite. Важно помнить:

* Движение, описанное в update(), будет непрерывным и не зависит от частоты кадров (FPS) напрямую, так как метод вызывается каждый кадр. Однако для создания FPS-независимого движения требуются более сложные расчеты с учетом дельты времени. * Свойство this.game.config.width содержит ширину игрового холста, заданную в конфигурации (или рассчитанную по умолчанию). Аналогично доступно this.game.config.height. * Операция += модифицирует текущее значение переменной. Это стандартный и лаконичный способ инкремента.

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

Вы освоили базовый паттерн движения объектов в Phaser: загрузка, создание и обновление позиций в игровом цикле. Для экспериментов попробуйте: изменить скорость движения, задав другое значение вместо 4; реализовать движение по вертикали или диагонали; использовать this.game.config.height для «отскока» от нижней границы; добавить управление с клавиатуры, изменяя `xиy` по нажатию клавиш.