← На главную
Серия руководств

Шаг 1. Создание тайла

Создание Tower Defense с PIXI • Шаг 1 из 12

В этом курсе мы создадим игру в жанре tower defense с помощью PixiJS.

Дополнительные материалы

Перед началом разработки нужно выполнить два шага:

1️⃣ ( Скачайте наш шаблон проекта PIXI. Можно сразу начать работу над игрой или изучить руководство по созданию шаблона PIXI.

2️⃣ Скачайте игровые ресурсы:

Мы скачали и распаковали шаблон проекта, в котором продолжим работу. Обычно я начинаю новую игру с фонового изображения. Здесь вместо него используем полную карту уровня, заранее подготовленную в Tiled в формате tilemap. Вся карта состоит из небольших тайлов. Данные уровня хранятся в двух файлах:

  • tilemap.json
  • tilemap.png

Разместим их в нужных папках проекта:

  • /src/json/tilemap.json
  • /src/sprites/tilemap.png

Для создания карты на сцене сначала научимся разбирать изображение tilemap.png, чтобы рисовать только нужные тайлы.

Создадим класс Tile, отвечающий за отрисовку нужной части карты:

import { EventEmitter } from "events";
import * as PIXI from "pixi.js";
import { App } from "../system/App";

export class Tile extends EventEmitter {
    constructor(id) {
        super();
        this.atlas = App.res("tilemap");
        this.id = id;
        this.createSprite();
    }

    createSprite() {
    }
}

Tile будет наследоваться от EventEmitter, чтобы экземпляры могли отправлять нужные события. Например, башня — разновидность Tile. У неё могут быть события, которые в дальнейшем понадобится отслеживать.

В this.atlas получим текстуру загруженного ресурса tilemap. Пусть у каждого тайла будет свой ID в атласе, по которому можно определить его положение. Прежде чем рисовать нужную часть изображения, определим её позицию по ID.

Сначала вручную зададим число строк и столбцов изображения атласа tilemap.png в конфигурации игры и укажем размер тайлов:


import { Tools } from "../system/Tools";
import { GameScene } from "./GameScene";

export const Config = {
    loader: Tools.massiveRequire(require["context"]('./../../sprites/', true, /\.(mp3|png|jpe?g)$/)),
    scenes: {
        "Game": GameScene
    },
    atlas: {
        cols: 23,
        rows: 13,
        tileSize: 64
    }    
};

Зная число строк и столбцов атласа, вычислим, в какой строке и столбце находится тайл с заданным ID:

    get position() {
        let index = 0;

        for (let row = 0; row < App.config.atlas.rows; row++) {
            for (let col = 0; col < App.config.atlas.cols; col++) {
                ++index;
                if (index === this.id) {
                    return {row, col};
               
               }
            }
        }

        return {row: 0, col: 0};
    }

Определив строку и столбец тайла в сетке tilemap, наконец можем его нарисовать:

    createSprite() {
        const x = App.config.atlas.tileSize * this.position.col;
        const y = App.config.atlas.tileSize * this.position.row;
        const texture = new PIXI.Texture(this.atlas, new PIXI.Rectangle(x + 1, y + 1, App.config.atlas.tileSize - 2, App.config.atlas.tileSize - 2));
        this.sprite = new PIXI.Sprite(texture);
        this.sprite.anchor.set(0.5);
    }

Находим координаты тайла по его месту в сетке с учётом размера. Здесь используем отступ 1px от каждого края: карта была сгенерирована с таким отступом для предотвращения наложения кадров.

Осталось проверить правильность создания тайлов:

import { Scene } from '../system/Scene';
import { Tile } from './Tile';

export class GameScene extends Scene {
    create() {
        const tile = new Tile(1);
        this.container.addChild(tile.sprite);
    }
}