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

Создание игрового мира с препятствиями — ключевая задача для любого разработчика. В Phaser Arcade Physics для этого используются простые, но мощные методы `collider` и `overlap`. В этой статье мы разберем, как загружать тайловую карту, настраивать столкновения и реагировать на взаимодействия между спрайтом и тайлами. Вы научитесь управлять физическими взаимодействиями в вашей игре, используя стандартный пример из документации Phaser.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    cursors;
    player;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/tile_properties.json');
        this.load.image('tiles', 'assets/tilemaps/tiles/gridtiles.png');
        this.load.image('ball', 'assets/sprites/orb-blue.png');
    }

    create ()
    {
        const map = this.make.tilemap({ key: 'map' });
        const tileset = map.addTilesetImage('tiles');
        const layer = map.createLayer('Tile Layer 1', tileset, 0, 0);

        map.setCollision([ 34, 20 ]); // 20 = dark gray, 32 = dark blue
        // map.setCollision([ 136 ]); // dark brown
        // map.setCollision([ 80 ]); // yellow
        // map.setCollision([ 122 ]); // light brown

        this.player = this.physics.add.sprite(48, 48, 'ball');

        this.physics.add.collider(this.player, layer);

        // this.physics.add.collider(player, layer, () => {
        //     console.log('colliding');
        // });

        // this.physics.add.overlap(player, layer, () => {
        //     console.log('overlapping');
        // });

        this.cursors = this.input.keyboard.createCursorKeys();
    }

    update (time, delta)
    {
        this.player.setVelocity(0);

        // Horizontal movement
        if (this.cursors.left.isDown)
        {
            this.player.setVelocityX(-100);
        }
        else if (this.cursors.right.isDown)
        {
            this.player.setVelocityX(100);
        }

        // Vertical movement
        if (this.cursors.up.isDown)
        {
            this.player.setVelocityY(-100);
        }
        else if (this.cursors.down.isDown)
        {
            this.player.setVelocityY(100);
        }
    }
}

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

const game = new Phaser.Game(config);

Подготовка карты и слоя

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

В методе create происходит основная инициализация. Сначала создается объект тайловой карты, затем к ней добавляется набор тайлов (tileset) и, наконец, визуальный слой.

const map = this.make.tilemap({ key: 'map' });
const tileset = map.addTilesetImage('tiles');
const layer = map.createLayer('Tile Layer 1', tileset, 0, 0);

Настройка столкновений для тайлов

Не все тайлы на карте должны быть препятствиями. Метод setCollision позволяет указать, с какими индексами тайлов будет происходить физическое столкновение. Индексы соответствуют номерам тайлов в tileset.

В примере изначально активны столкновения с тайлами 34 и 20. Закомментированные строки показывают, как можно быстро переключать, какие тайлы являются твердыми.

map.setCollision([ 34, 20 ]); // 20 = dark gray, 32 = dark blue
// map.setCollision([ 136 ]); // dark brown
// map.setCollision([ 80 ]); // yellow
// map.setCollision([ 122 ]); // light brown

Создание игрока и физического взаимодействия

Игрок создается как физический спрайт с помощью this.physics.add.sprite. После этого необходимо определить, как он будет взаимодействовать со слоем тайлов. Phaser Arcade Physics предлагает два основных метода:

1.  `this.physics.add.collider` — объекты будут сталкиваться и отталкиваться друг от друга.
2.  `this.physics.add.overlap` — объекты будут физически проходить друг сквозь друга, но мы сможем зафиксировать факт их перекрытия.

В примере по умолчанию используется коллайдер, который обеспечивает классическое поведение стены.

this.player = this.physics.add.sprite(48, 48, 'ball');
this.physics.add.collider(this.player, layer);

Разница между Collider и Overlap

В закомментированном коде примера показаны оба варианта с callback-функциями. Это ключевой момент для геймдизайна.

* **Коллайдер с callback**: Вызовется в момент столкновения и *остановки* объекта. Подходит для нанесения урона при ударе, звука удара. * **Оверлап с callback**: Вызовется, когда хитбоксы объектов начинают пересекаться, и будет вызываться постоянно, пока они пересекаются. Идеален для зон, наносящих периодический урон, сбора предметов или активации ловушек.

// При столкновении
this.physics.add.collider(player, layer, () => {
    console.log('colliding');
});

// При перекрытии (нахождении в одной области)
this.physics.add.overlap(player, layer, () => {
    console.log('overlapping');
});

Управление движением игрока

Чтобы игрок мог сталкиваться с тайлами, им нужно управлять. В методе update каждый кадр сначала обнуляется скорость, чтобы движение было отзывчивым и прекращалось при отпускании клавиши. Затем проверяется состояние клавиш-стрелок и устанавливается соответствующая скорость по осям X и Y.

this.player.setVelocity(0);

if (this.cursors.left.isDown) { this.player.setVelocityX(-100); }
else if (this.cursors.right.isDown) { this.player.setVelocityX(100); }

if (this.cursors.up.isDown) { this.player.setVelocityY(-100); }
else if (this.cursors.down.isDown) { this.player.setVelocityY(100); }

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

Используя setCollision, collider и overlap, вы можете быстро создавать сложные игровые миры с физикой. Для экспериментов попробуйте

  1. Активировать разные наборы тайлов для столкновений
  2. Заменить collider на overlap и реализовать зону, которая наносит урон при нахождении в ней
  3. Добавить в callback-функцию overlap изменение цвета спрайта игрока, пока он находится на "опасном" тайле