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

Векторная математика — основа динамики в играх. Понимание операций над векторами, таких как нахождение противоположного направления, критически важно для реализации движения, отражений и поведения ИИ. В этой статье мы разберем простой, но наглядный пример, показывающий, как работает метод `negate()` у вектора `Phaser.Math.Vector2` в реальном времени, реагируя на движение курсора. Это поможет вам интуитивно понять, как легко менять направление вектора в своих проектах.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        const graphics = this.add.graphics({ fillStyle: { color: 0x2266aa } });

        const point = new Phaser.Math.Vector2(450, 350);

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

            point.x = pointer.x - 400;
            point.y = pointer.y - 300;

            redraw();
        });

        redraw();

        function redraw ()
        {
            graphics.clear();

            // draw as if 400/300 was the center
            graphics.fillPoint(400 + point.x, 300 + point.y, 15);

            point.negate();

            graphics.fillStyle(0x00aa00);
            graphics.fillPoint(400 + point.x, 300 + point.y, 15);
        }
    }
}

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

const game = new Phaser.Game(config);

Что делает этот пример?

Программа создает интерактивную сцену с двумя точками. Исходная (синяя) точка следует за курсором мыши, но относительно смещенного центра. Ее противоположная (зеленая) точка мгновенно вычисляется методом negate() и отображается симметрично относительно центра экрана (координаты 400, 300). Движение мыши заставляет обе точки перемещаться зеркально.

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

Разбор структуры кода

Код представляет собой стандартную сцену Phaser. В методе create() инициализируется графика, создается векторная точка и подписывается на событие движения указателя.

class Example extends Phaser.Scene
{
    create ()
    {
        const graphics = this.add.graphics({ fillStyle: { color: 0x2266aa } });

        const point = new Phaser.Math.Vector2(450, 350);

        this.input.on('pointermove', pointer =>
        {
            point.x = pointer.x - 400;
            point.y = pointer.y - 300;
            redraw();
        });
        redraw();
        // ... функция redraw
    }
}

Конфигурация игры задает окно 800x600 пикселей и связывает сцену.

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

Сердце программы: функция redraw()

Вся логика отрисовки инкапсулирована во вспомогательной функции redraw(). Она вызывается при инициализации и при каждом движении мыши.

function redraw ()
{
    graphics.clear();
    // draw as if 400/300 was the center
    graphics.fillPoint(400 + point.x, 300 + point.y, 15);
    point.negate();
    graphics.fillStyle(0x00aa00);
    graphics.fillPoint(400 + point.x, 300 + point.y, 15);
}

Ключевые шаги: 1. graphics.clear(): Очищает холст от предыдущего кадра. 2. graphics.fillPoint(400 + point.x, 300 + point.y, 15): Рисует синюю точку. Координаты вектора point изначально рассчитаны относительно центра (400,300), поэтому для отрисовки на экране мы прибавляем этот центр обратно. 3. point.negate(): **Это ключевой вызов.** Метод модифицирует сам вектор point, меняя знак его компонентов `xиyна противоположный. Теперьpoint` хранит уже отрицательные значения. 4. Смена стиля и отрисовка зеленой точки с новыми (отрицательными) координатами, также смещенными к центру. В результате она всегда находится зеркально синей точке относительно центра (400,300).

Важные детали и практические аспекты

Обратите внимание на несколько нюансов, важных для практического применения:

* **Изменение на месте:** Метод negate() не создает новый вектор, а изменяет существующий. Если исходный вектор нужно сохранить, следует сначала скопировать его с помощью clone(). * **Относительные координаты:** Логика примера построена на работе в относительной системе координат с центром в (400,300). Вектор point хранит смещение от этого центра. Это распространенный подход для упрощения геометрических расчетов. * **Событийный цикл:** Функция redraw() вызывается в обработчике pointermove, обеспечивая плавную и мгновенную реакцию на действия пользователя. Это основа для любого интерактивного поведения в Phaser.

Пример использования negate() для отражения скорости мяча от стенки:

// При столкновении с горизонтальной стенкой инвертируем вертикальную скорость
ball.body.velocity.y *= -1;
// То же самое, но через вектор и метод negate()
ball.body.velocity.y = -ball.body.velocity.y;
// Если нужно инвертировать весь вектор скорости
ball.body.velocity.negate();

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

Метод negate() — это мощный и простой инструмент для работы с направлениями. Он мгновенно превращает вектор в его противоположность, что незаменимо для расчета отскоков, направления взгляда врага на игрока или зеркальных трансформаций. Попробуйте поэкспериментировать с примером: измените центр симметрии, добавьте третью точку, которая использует negate() только по одной оси (например, point.x = -point.x), или привяжите эту логику к скорости спрайта, чтобы управлять его движением с помощью мыши.