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

Интерактивность — основа вовлечения в игру. Один из базовых паттернов, который должен освоить каждый разработчик, — это перетаскивание и рисование объектов с помощью мыши или касаний. В этой статье мы разберём классический пример рисования прямоугольника при зажатой кнопке мыши, используя нативные события ввода Phaser. Этот подход станет фундаментом для реализации таких механик, как выделение юнитов, рисование траектории полёта или создание пользовательских уровней.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        const graphics = this.add.graphics();

        const color = 0xffff00;
        const thickness = 2;
        const alpha = 1;

        //  Events

        let draw = false;

        this.input.on('pointerdown', pointer =>
        {

            draw = true;

        });

        this.input.on('pointerup', () =>
        {

            draw = false;

        });

        this.input.on('pointermove', pointer =>
        {

            if (draw)
            {
                graphics.clear();
                graphics.lineStyle(thickness, color, alpha);
                graphics.strokeRect(pointer.downX, pointer.downY, pointer.x - pointer.downX, pointer.y - pointer.downY);
            }

        });
    }
}

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

const game = new Phaser.Game(config);

Настройка сцены и слушателей событий

Всё начинается в методе create нашего класса сцены. Первым делом мы создаём объект Graphics, который будет использоваться для рисования примитивов.

const graphics = this.add.graphics();

Затем мы настраиваем три обработчика событий ввода: pointerdown, pointerup и pointermove. Они срабатывают при нажатии кнопки мыши, её отпускании и перемещении курсора соответственно. Для управления состоянием рисования используется простая булева переменная draw.

let draw = false;

this.input.on('pointerdown', pointer => {
    draw = true;
});

this.input.on('pointerup', () => {
    draw = false;
});

Логика рисования в обработчике pointermove

Основная магия происходит в обработчике события pointermove. Этот метод вызывается каждый кадр, когда курсор мыши перемещается. Однако рисовать прямоугольник мы хотим только в тот момент, когда кнопка мыши зажата (то есть когда draw === true).

this.input.on('pointermove', pointer => {
    if (draw)
    {
        // Код рисования здесь
    }
});

Внутри этого условия мы выполняем три ключевых действия: очищаем предыдущую графику, задаём стиль линии и рисуем сам прямоугольник. Важно понимать, что graphics.clear() вызывается каждый кадр, чтобы стереть предыдущий прямоугольник и нарисовать новый — это создаёт эффект плавного перетаскивания и изменения размера фигуры.

Использование координат Pointer объекта

Для определения размеров и положения прямоугольника мы используем свойства объекта pointer, который передаётся в обработчики событий. Это специальный объект Phaser, содержащий информацию о состоянии ввода.

Ключевые свойства для нашей задачи: * pointer.downX и pointer.downY — координаты точки, где кнопка мыши была изначально нажата. Это фиксированная верхняя левая точка нашего прямоугольника. * pointer.x и pointer.y — текущие координаты курсора. Они постоянно меняются при движении мыши.

Формула для ширины и высоты прямоугольника проста: текущая_координата - начальная_координата. Это позволяет рисовать прямоугольник в любом направлении (например, справа налево или снизу вверх).

graphics.lineStyle(thickness, color, alpha);
graphics.strokeRect(pointer.downX, pointer.downY, pointer.x - pointer.downX, pointer.y - pointer.downY);

Метод strokeRect рисует только контур прямоугольника. Если вам нужна заливка, используйте fillRect.

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

Вы реализовали базовую систему рисования прямоугольника по перетаскиванию мыши, используя всего около 30 строк кода. Это идеальный фундамент. Для экспериментов попробуйте

  1. рисовать не только контур, но и залитую фигуру, используя fillRect
  2. сохранять нарисованные прямоугольники в массив, чтобы они не исчезали после отпускания кнопки
  3. добавить обработку мультитача для мобильных устройств, используя pointer1 и pointer2
  4. изменить логику, чтобы прямоугольник рисовался не от угла к углу, а от центра