Рефакторинг кода

Новый модуль подземелья будет более функциональным, чем раньше, поскольку он будет использоваться для управления как рендерингом уровня, так и перемещениями игровых объектов. Раньше наш класс игрока, когда ему нужно было переместиться, изменял тайловую карту слоя напрямую. После нашего рефакторинга этот класс для перемещения будет вызывать функции, предоставляемые модулем подземелья. Цель состоит в том, чтобы облегчить последующее развитие классов монстров: если каждый класс игровой сущности непосредственно будет анализировать и изменять карту тайлов, то это было бы довольно сложно поддерживать, поскольку любое изменение потребует изменений в нескольких классах.

Исходный код для первого примера, использованного в этой главе, находится в chapter-4/example-1-tween-movement/.

Инициализация подземелья

Функция инициализации подземелья в значительной степени та же: мы просто переместили некоторые переменные, чтобы облегчить к ним доступ для других функций. Новая функция инициализации выглядит так:

initialize: function (scene) {
    this.scene = scene
    this.level = level
    let levelWithTiles = level.map(r => r.map(t => t == 1 ? this.sprites.wall : this.sprites.floor))

    const config = {
        data: levelWithTiles,
        tileWidth: this.tileSize,
        tileHeight: this.tileSize,
    }
    const map = scene.make.tilemap(config)
    const tileset = map.addTilesetImage('tiles', 'tiles', this.tileSize, this.tileSize, 0, 1) 
    this.map = map.createLayer(0, tileset, 0, 0)

},

Она практически не изменилась — мы просто переместили некоторые переменные, чтобы они стали частью объекта dungeon. В конце этой функции мы устанавливаем следующие свойства :

  • dungeon.scene — в нем хранится ссылка на сцену Phaser.
  • dungeon.map — в нем хранится ссылка на слой Phaser, используемый для тайлов земли.
  • dungeon.level — в котором хранится ссылка на исходный массив, используемый для данных уровня.

Основные дополнения к модулю подземелий связаны с движением игровых сущностей, и это то, что мы сделаем дальше.

Поддержка движения

В предыдущей главе игрок был просто плиткой на тайловой карте, и движение происходило путем замены тайла назначения на тайл с игроком и в исходной позиции — на тайл пола. Мы также проведем рефакторинг и изменим анимацию спрайтов. Причина этого рефакторинга в том, что спрайты можно анимировать с помощью анимации движения, и мы переключимся на этот способ.

Спрайты — это свободно плавающие игровые объекты, которые размещаются в игровом мире. Обычно игровые объекты, такие как игрок, враги, пули и другие объекты, с которыми игрок взаимодействует или перемещается в пейзаже, обычно создаются спрайтами в 2D-играх.

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

Промежуточные кадры позволяют нам изменять свойства игровых объектов с течением времени. Мы будем использовать их для управления положением игрового объекта от тайла к следующему в течение нескольких миллисекунд. Вместо того, чтобы мгновенно телепортироваться между плитками, персонаж игрока будет перемещаться с одной плитки на другую.

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

Инициализация сущностей

Так же, как есть функция инициализации для уровня, мы реализуем функцию с именем initializeEntity, чтобы настроить спрайт для данной сущности и добавить его в подземелье. Эта функция будет вызываться конструкторами наших игровых сущностей.