Создание кирпичей

Это 9 из 16 уроков руководства разработки игры с помощью Phaser. Исходный код этого урока вы можете найти здесь: Gamedev-Phaser-Content-Kit/demos/lesson09.html.

Создать поле кирпичей немного сложнее, чем просто добавить объект на экран, но всё же, благодаря Phaser, нам будет полегче, по сравнению с чистым JavaScript. Давайте разберёмся, как создать набор кирпичей и нарисовать их всех, используя цикл.

Определяем переменные

Сначала, давайте определим необходимые переменные — добавьте следующий код ниже всех наших текущих определений переменных:

var bricks;
var newBrick;
var brickInfo;

Переменная bricks будет использоваться в качестве набора кирпичей, newBrick будет тем самым кирпичом, который мы будем создавать в каждой итерации цикла и добавлять в набор, а в brickInfo будет хранить всю необходимую информацию о кирпичах, как таковых.

Добавляем графику для кирпича

Далее, давайте загрузим изображение кирпича brick, при помощи ещё одного вызова функции load.image():

function preload() {
    // ...
    game.load.image('brick', 'img/brick.png');
}

Не забудьте скачать изображение кирпича с Github в папку /img.

Рисуем кирпичи

Для удобства, давайте вынесем код отрисовки кирпичей в отдельную функцию initBricks и вызовем её в конце функции create():

function create(){
    // ...
    initBricks();
}

Теперь перейдём непосредственно к самой функции. Добавим функцию initBricks() в самый конец нашего кода, прямо перед </script>, а в теле этой функции опишем объект brickInfo, который нам скоро понадобится:

function initBricks() {
    brickInfo = {
        width: 50,
        height: 20,
        count: {
            row: 3,
            col: 7
        },
        offset: {
            top: 50,
            left: 60
        },
        padding: 10
    };
}

Объект brickInfo содержит всю необходимую нам информацию о кирпичах: ширина и высота кирпичика, количество рядов и столбцов кирпичей, которые мы хотим отрисовать на игровом поле, отступы от левого и верхнего края экрана (место на <canvas>, откуда мы начнём располагать кирпичи) и зазоры между самими кирпичами.

А теперь, собственно, к кирпичам — инициализируйте пустой набор для хранения кирпичей, путём добавления следующей строчки кода в функцию initBricks():

bricks = game.add.group();

Далее переберём в цикле ряды и столбцы — добавьте следующий код со вложенным циклом после предыдущей строки:

for(c=0; c<brickInfo.count.col; c++) {
    for(r=0; r<brickInfo.count.row; r++) {
        // create new brick and add it to the group
    }
}

Теперь необходимо в каждой итерации создавать кирпич, чтобы получить необходимое число кирпичей, нарисовать их всех на экране и добавить в наш набор bricks. Для этого добавим во вложенный цикл немного кода, как показано ниже:

for(c=0; c<brickInfo.count.col; c++) {
    for(r=0; r<brickInfo.count.row; r++) {
        var brickX = 0;
        var brickY = 0;
        newBrick = game.add.sprite(brickX, brickY, 'brick');
        game.physics.enable(newBrick, Phaser.Physics.ARCADE);
        newBrick.body.immovable = true;
        newBrick.anchor.set(0.5);
        bricks.add(newBrick);
    }
}

Вот мы и создали новый кирпич в каждой итерации и отрисовали его на экране. Как мы помним из урока 5, мы используем движок Arcade Physics. К каждому новому кирпичу применяем физику из этого движка и делаем его неподвижным, чтобы мячик его не сбивал, а, также, устанавливаем якорь кирпича в его середину. После этого, добавляем кирпич в набор bricks.

Но у нас осталась проблема — все кирпичи мы рисуем в одном и том же месте, в координатах (0,0). Чтобы это исправить, давайте добавим вычисление координат brickX и brickY в каждой итерации. Обновите строки инициализации этих переменных, как показано ниже:

var brickX = (c*(brickInfo.width+brickInfo.padding))+brickInfo.offset.left;
var brickY = (r*(brickInfo.height+brickInfo.padding))+brickInfo.offset.top;

Координата x каждого кирпича рассчитывается на основе суммы ширины кирпича brickInfo.width и зазора brickInfo.padding, умноженной на номер столбца с, после этого добавляем отступ от левого края brickInfo.offset.left; Расчёт y аналогичен, только используются номер ряда r, высота кирпича brickInfo.height и отступ от верхнего края brickInfo.offset.top. Вот теперь каждый кирпич на своём месте, с учётом всех отступов и зазоров.

Проверяем код функции initBricks()

Вот итоговый код функции initBricks():

function initBricks() {
    brickInfo = {
        width: 50,
        height: 20,
        count: {
            row: 3,
            col: 7
        },
        offset: {
            top: 50,
            left: 60
        },
        padding: 10
    }
    bricks = game.add.group();
    for(c=0; c<brickInfo.count.col; c++) {
        for(r=0; r<brickInfo.count.row; r++) {
            var brickX = (c*(brickInfo.width+brickInfo.padding))+brickInfo.offset.left;
            var brickY = (r*(brickInfo.height+brickInfo.padding))+brickInfo.offset.top;
            newBrick = game.add.sprite(brickX, brickY, 'brick');
            game.physics.enable(newBrick, Phaser.Physics.ARCADE);
            newBrick.body.immovable = true;
            newBrick.anchor.set(0.5);
            bricks.add(newBrick);
        }
    }
}

Если вы перезапустите страницу index.html, то увидеть кирпичи, нарисованные на расстоянии друг от друга.

Сравните свой код

Вы можете проверить код из этого урока и поиграть с ним, чтобы лучше понять, как он работает:

Следующий шаг

Кажется, что-то не так. Ах да! Мячик же проходит сквозь кирпичи. Добавим обработку коллизий.