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

Реализация движения объектов к заданной точке — частая задача в играх: от преследования врагом игрока до отправки снаряда в цель. Phaser 3 предлагает для этого элегантное решение в рамках Arcade Physics. В этой статье мы разберем, как заставить спрайт плавно двигаться к цели с заданной скоростью, используя встроенный метод `physics.moveToObject`. Этот подход избавляет от ручных вычислений векторов и идеально подходит для прототипирования механик преследования или запуска снарядов.

Версия 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('flower', 'assets/sprites/flower-exo.png');
        this.load.image('cursor', 'assets/sprites/drawcursor.png');
    }

    create ()
    {
        const flower = this.physics.add.image(100, 300, 'flower')
            .setBounce(1, 1)
            .setCollideWorldBounds(true);

        const cursor = this.add.image(0, 0, 'cursor').setVisible(false);

        this.add.text(10, 10, 'Click to set target', { fill: '#00ff00' });

        this.input.on('pointerdown', (pointer) =>
        {
            cursor.copyPosition(pointer).setVisible(true);

            // Move toward target at 200 px/s:
            this.physics.moveToObject(flower, cursor, 200);

            // See <move and stop at position.js> for stopping.
        });
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: { debug: true }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Подготовка сцены и объектов

В методе preload загружаются два изображения: главный объект flower и курсор-цель cursor. Обратите внимание, что пример использует базовый URL для загрузки ассетов из репозитория примеров Phaser.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('flower', 'assets/sprites/flower-exo.png');
    this.load.image('cursor', 'assets/sprites/drawcursor.png');
}

В create создается физический спрайт flower. Ключевые моменты: использование this.physics.add.image и настройка свойств физики. Метод setBounce(1, 1) делает объект абсолютно упругим, а setCollideWorldBounds(true) — ограничивает его движение границами мира. Объект cursor создается как обычное изображение и изначально скрыт.

const flower = this.physics.add.image(100, 300, 'flower')
    .setBounce(1, 1)
    .setCollideWorldBounds(true);

const cursor = this.add.image(0, 0, 'cursor').setVisible(false);

Обработка клика и установка цели

Пользовательский интерфейс прост: текст-подсказка и обработчик события клика (pointerdown). При клике позиция курсора (скрытого спрайта cursor) обновляется, и он становится видимым. Это визуализирует точку, к которой будет двигаться цветок.

this.add.text(10, 10, 'Click to set target', { fill: '#00ff00' });

this.input.on('pointerdown', (pointer) =>
{
    cursor.copyPosition(pointer).setVisible(true);
    // ... Движение будет здесь
});

Метод copyPosition() копирует координаты указателя мыши в спрайт cursor. Важно: cursor — это не физическое тело, а обычный спрайт, используемый лишь как визуальный маркер и целевая точка для вычислений.

Магия метода physics.moveToObject

Вся логика движения умещается в одну строку внутри обработчика клика. Метод this.physics.moveToObject автоматически вычисляет вектор скорости для физического тела (flower), чтобы оно начало движение к целевому объекту (cursor) с указанной постоянной скоростью.

// Move toward target at 200 px/s:
this.physics.moveToObject(flower, cursor, 200);

**Что происходит внутри:** 1. Система физики Arcade берет текущие мировые координаты flower и cursor. 2. Рассчитывается направление от цветка к курсору. 3. Устанавливаются свойства body.velocity.x и body.velocity.y спрайта flower таким образом, чтобы результирующая скорость (длина вектора) была равна 200 пикселей в секунду. 4. Движение начинается мгновенно. Объект будет продолжать движение с этой скоростью и направлением, пока его скорость не будет изменена другим кодом или физическим взаимодействием (например, столкновением).

**Важное замечание:** В этом примере объект не останавливается при достижении цели. Он будет двигаться дальше, пока не столкнется с границей мира и не отскочит от нее (благодаря setBounce(1, 1)).

Конфигурация игры и физики

Для работы примера необходима правильная настройка конфигурации игры. Самое важное — активация физического движка Arcade и включение отладки.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade', // Используем Arcade Physics
        arcade: { debug: true } // Включаем отладочные отображение хитбоксов
    },
    scene: Example
};

Параметр debug: true подсвечивает физические тела (цветок) зеленой рамкой, что позволяет наглядно видеть его границы и убедиться, что движение и отскок работают корректно. В продакшене его обычно отключают.

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

Метод physics.moveToObject — это мощный и лаконичный инструмент для реализации движения к цели в Phaser 3. Он идеально подходит для быстрого прототипирования механик, где требуется «запустить объект из точки A в точку B». Для дальнейших экспериментов попробуйте: изменить скорость в зависимости от расстояния до цели; реализовать остановку объекта при достижении цели (используя проверку расстояния в update); применить метод к группе объектов, чтобы создать «рой» преследователей; или комбинировать его с другими силами Arcade Physics, такими как ускорение или трение.