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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    a = 0;
    graphics;
    rectangles;
    rect;

    create ()
    {
        this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x0000aa }, fillStyle: { color: 0xaa0000 }});

        this.rect = new Phaser.Geom.Rectangle(0, 0, 30, 30);

        this.rectangles = [];

        for (let x = 0; x < 10; x++)
        {
            for (let y = 0; y < 10; y++)
            {
                this.rectangles.push(new Phaser.Geom.Rectangle(x * 80, y * 60, 80, 60));
            }
        }
    }

    update ()
    {
        this.a += 0.005;

        if (this.a > Math.PI * 2)
        {
            this.a -= Math.PI * 2;
        }

        this.rect.x = 370 - Math.cos(this.a) * 370;
        this.rect.y = 270 - Math.sin(this.a * 2) * 270;

        this.graphics.clear();
        this.graphics.fillRectShape(this.rect);

        // stroke blue all rectangles NOT containing rect
        this.graphics.lineStyle(1, 0x0000aa);

        for (let i = 0; i < this.rectangles.length; i++)
        {
            if (!Phaser.Geom.Rectangle.ContainsRect(this.rectangles[i], this.rect))
            {
                this.graphics.strokeRectShape(this.rectangles[i]);
            }
        }

        // stroke red all rectangles that DO contain rect
        this.graphics.lineStyle(2, 0xaa0000);

        for (let i = 0; i < this.rectangles.length; i++)
        {
            if (Phaser.Geom.Rectangle.ContainsRect(this.rectangles[i], this.rect))
            {
                this.graphics.strokeRectShape(this.rectangles[i]);
            }
        }
    }
}

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

const game = new Phaser.Game(config);

Как работает метод ContainsRect

Статический метод Phaser.Geom.Rectangle.ContainsRect(rectA, rectB) проверяет, полностью ли содержится прямоугольник rectB внутри прямоугольника rectA. Он возвращает true только в том случае, если все четыре угла прямоугольника rectB находятся внутри границ rectA. Это важно: если прямоугольники лишь частично пересекаются, метод вернет false. В предоставленном примере этот метод используется для визуального разделения сетки прямоугольников на две группы.

if (Phaser.Geom.Rectangle.ContainsRect(this.rectangles[i], this.rect))
{
    // Этот код выполнится, если маленький прямоугольник
    // полностью внутри текущего прямоугольника сетки
}

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

В методе create() происходит инициализация графики, создание движущегося прямоугольника (this.rect) и статической сетки из 100 прямоугольников (this.rectangles). Сетка создается с помощью двойного цикла for и заполняет массив экземплярами Phaser.Geom.Rectangle.

create ()
{
    this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x0000aa }, fillStyle: { color: 0xaa0000 }});
    this.rect = new Phaser.Geom.Rectangle(0, 0, 30, 30);
    this.rectangles = [];
    for (let x = 0; x < 10; x++)
    {
        for (let y = 0; y < 10; y++)
        {
            this.rectangles.push(new Phaser.Geom.Rectangle(x * 80, y * 60, 80, 60));
        }
    }
}

Анимация и логика обводки в update()

Каждый кадр в update() маленький прямоугольник this.rect движется по сложной траектории с использованием тригонометрических функций. Затем вся графика очищается (this.graphics.clear()), и маленький прямоугольник заливается красным цветом.

Далее выполняется ключевая логика: сначала обходом всех прямоугольников сетки обводятся синим (lineStyle(1, 0x0000aa)) те, которые НЕ содержат маленький прямоугольник. Затем, в следующем цикле, устанавливается более толстый стиль линии красного цвета (lineStyle(2, 0xaa0000)) и обводятся только те прямоугольники сетки, которые ДЕЙСТВИТЕЛЬНО содержат маленький прямоугольник согласно проверке ContainsRect.

// Обводим синим прямоугольники, НЕ содержащие this.rect
this.graphics.lineStyle(1, 0x0000aa);
for (let i = 0; i < this.rectangles.length; i++)
{
    if (!Phaser.Geom.Rectangle.ContainsRect(this.rectangles[i], this.rect))
    {
        this.graphics.strokeRectShape(this.rectangles[i]);
    }
}
// Обводим красным прямоугольники, содержащие this.rect
this.graphics.lineStyle(2, 0xaa0000);
for (let i = 0; i < this.rectangles.length; i++)
{
    if (Phaser.Geom.Rectangle.ContainsRect(this.rectangles[i], this.rect))
    {
        this.graphics.strokeRectShape(this.rectangles[i]);
    }
}

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

Этот метод — отличный инструмент для точечных проверок, где важна полная вложенность объекта. * **Стратегии и головоломки:** Проверка, полностью ли юнит или фигура находится внутри клетки игрового поля перед совершением хода. * **Интерфейсы и редакторы:** Определение, попал ли перетаскиваемый элемент целиком в область дроп-зоны. * **Логика камеры:** Проверка, находится ли важный игровой объект полностью в поле зрения камеры, чтобы принять решение о ее прокрутке.

Для проверки простого пересечения (когда фигуры хотя бы касаются) следует использовать другие методы, например, Phaser.Geom.Rectangle.Overlaps().

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

Метод Phaser.Geom.Rectangle.ContainsRect() предоставляет простой и эффективный способ проверить полное вхождение одного прямоугольника в другой. Это мощный инструмент для реализации точной логики областей в вашей игре. Для экспериментов попробуйте изменить размер движущегося прямоугольника, чтобы увидеть, как меняется картина обводки, или использовать проверку ContainsRect для активации событий (например, воспроизведения звука) при полном заходе игрока в определенную зону уровня.