Вы находитесь на странице: 1из 10

Пишем HTML5-игру за 20 минут, или

введение в Phaser framework


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

Введение

Phaser — это движок для разработки мобильных и десктопных HTML5 игр, базирующийся
на библиотеке PIXI.js. Поддерживает рендеринг в Canvas и WebGL, анимированные
спрайты, частицы, аудио, разные способы ввода и физику объектов. Исходники доступны
как для просмотра, так и для свободной модификации. Он создан Ричардом Дейви
(Richard Davey), известному благодаря активному участию в сообществе программистов,
использующих Flixel framework. Ричард не скрывает, что вдохновлялся Фликселем,
поэтому некоторые вещи в Фазере будут знакомы опытным флешерам. Первая версия
нового движка вышла 13 сентября этого года, сейчас ведется не только активное развитие
библиотеки, но и написание документации, поэтому в данный момент уроков по ней,
мягко говоря, немного. Что, по моему скромному мнению, следует исправлять, и прямо
сейчас.

Установка библиотеки и локального веб-сервера

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


локальный веб-сервер. Все примеры из комплекта библиотеки используют PHP, поэтому и
сервер нужен соответствующий. Я использовал MAMP для MacOS, для Windows подойдет
отечественный Denwer или любой другой аналог.

После установки веб-сервера необходимо скачать последнюю версию Фазера c GitHub:


https://github.com/photonstorm/phaser. В данный момент (13 октября 2013 года)
рекомендую качать dev ветку, так как эта версия содержит в себе ряд очень полезных
изменений по сравнению с основной, в том числе и больший объем документации. Для
тех, кто не использует GitHub, доступна прямая ссылка на архив:
https://github.com/photonstorm/phaser/archive/dev.zip.

Чтобы убедиться, что все настроено правильно, можно запустить небольшое приложение-
пример Hello Phaser. Создайте папку hellophaser в директории вашего веб-сервера,
предназначенной для сайтов, и скопируйте туда три файла из папки Docs/Hello Phaser:
Запустите свой любимый браузер и откройте URL со скопированными файлами (в моем
случае http://localhost:8888/hellophaser/). Если все хорошо, вы увидите вращающийся
симпатичный логотип, такой как на скриншоте ниже:

Разработка игры

Подготовка необходимых фай лов

Теперь можно приступать к разработке нашей первой игры. Создайте для нее папку
phaser-pong на вашем веб-сервере и скопируйте туда файл phaser.js из папки build с
исходниками фреймворка. Также создайте в ней папку assets, где мы будем хранить все
ресурсы, относящиеся к игре, и файл index.html (собственно, здесь и будет наша игра).

Скопируйте в папку assets изображения шарика, ракетки и фона. Можно взять следующие
файлы (в качестве фона я взял звездное небо из примеров Фазера), а можно нарисовать
что-то свое. Главное — это убедиться, что вы загружаете в игру нужные картинки с
корректными именами и подходящими размерами. Также не стоит выбирать слишком
большие изображения, с их отрисовкой могут возникнуть проблемы. Поэтому перед
использованием фотографии своего кота уменьшите ее до, скажем, 480х640 (разрешение
нашей игры), и все будет хорошо.

В результате содержимое папки phaser-pong будет таким:


А в папке assets будет три картинки:

Создание главного объекта игры, загрузка ресурсов

Наконец-то все подготовительные этапы выполнены, и начинается собственно


разработка. Откройте index.html и вставьте туда следующий код:
<script src="phaser.js"></script>
<script type="text/javascript">
var game = new Phaser.Game(480, 640, Phaser.AUTO, '', { preload: preload,
create: create, update: update });
function preload() {
game.load.image('bet', 'assets/bet.png');
game.load.image('ball', 'assets/ball.png');
game.load.image('background', 'assets/starfield.jpg');
}
function create() {
game.add.tileSprite(0, 0, 480, 640, 'background');
}

function update () {
}
</script>
Откройте в браузере адрес новой игры (у меня это http://localhost:8888/phaser-pong/) и вы
увидите ее окно с нарисованным фоном

Что же происходит в написанном коде? Вначале мы импортируем библиотеку. Потом


создаем объект типа Game, задавая разрешение нашего приложения, в данном случае
ширину 480 и высоту 640 пикселей. Phaser.AUTO означает, что тип рендера будет
выбираться автоматически. При желании можно задать Canvas или WebGL. Четвертый
параметр задает родительский DOM-объект для игры, его мы не указываем.
В пятом параметре перечислены основные функции игры. preload() содержит код для
загрузки ресурсов, create() — инициализацию игры, а update() — команды,
выполняемые при обновлении приложения. На настольном компьютере update()
вызывается примерно 60 раз в секунду. Именно эта функция будет содержать в себе
основную игровую логику.
В функции create() мы добавляем статический спрайт с фоном нашей игры. Спрайт
заполняет пространство, указанное в первых четырех параметрах tileSprite.

Игровые объекты

Сейчас перейдем к самому интересному — наполним нашу игру логикой. После


объявления переменной game и перед функцией preload() объявим объекты с ракетками
игрока и компьютера, мячиком, а также укажем скорости их движения:
var playerBet;
var computerBet;
var ball;

var computerBetSpeed = 190;


var ballSpeed = 300;

Для создания ракеток напишем функцию createBet(x, y):


function createBet(x, y) {
var bet = game.add.sprite(x, y, 'bet');
bet.anchor.setTo(0.5, 0.5);
bet.body.collideWorldBounds = true;
bet.body.bounce.setTo(1, 1);
bet.body.immovable = true;

return bet;
}

Метод создает спрайт с указанными координатами и добавляет его в игру. Поле anchor
отвечает за точку отсчета координат спрайта, устанавливаем его по центру изображения
ракетки. body содержит в себе элементы для работы с физикой. Здесь мы ограничиваем
движение ракетки пределами игрового пространства, задаем силу «отскока» и
указываем, что при столкновении с объектами ракетка не будет отлетать в сторону.

Добавим два вызова этой функции в create(), сразу после создания фона. Ракетки будут
добавлены в игру после фонового изображения, поэтому мы будем их видеть на экране:
playerBet = createBet(game.world.centerX, 600);
computerBet = createBet(game.world.centerX, 20);

Аналогичным образом создадим шарик, дописав следующий код сразу после вызовов
функции createBet() в create():
ball = game.add.sprite(game.world.centerX, game.world.centerY,
'ball');
ball.anchor.setTo(0.5, 0.5);
ball.body.collideWorldBounds = true;
ball.body.bounce.setTo(1, 1);

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

Картинка получилась симпатичной, но думаю, стоит ее слегка оживить.


Добавляем переменную, отвечающую за состояние шарика и функцию, которая будет его
запускать:
var ballReleased = false;

function releaseBall() {
if (!ballReleased) {
ball.body.velocity.x = ballSpeed;
ball.body.velocity.y = -ballSpeed;
ballReleased = true;
}
}

Функция проверяет, что шарик еще не запущен, и в таком случае задает ему скорость с
помощью поля velocity.
Вызов функции повесим на нажатие кнопки мышки, написав следующую строку в create():
game.input.onDown.add(releaseBall, this);

Теперь клик мышкой запускает шарик, и он отскакивает от границ игры. Добавим


движения и ракеткам, отредактировав функцию update():
function update () {
//Управляем ракеткой игрока
playerBet.x = game.input.x;

var playerBetHalfWidth = playerBet.width / 2;

if (playerBet.x < playerBetHalfWidth) {


playerBet.x = playerBetHalfWidth;
}
else if (playerBet.x > game.width - playerBetHalfWidth) {
playerBet.x = game.width - playerBetHalfWidth;
}

//Управляем ракеткой компьютерного соперника


if(computerBet.x - ball.x < -15) {
computerBet.body.velocity.x = computerBetSpeed;
}
else if(computerBet.x - ball.x > 15) {
computerBet.body.velocity.x = -computerBetSpeed;
}
else {
computerBet.body.velocity.x = 0;
}
}

Ракетка игрока следует за указателем мыши, ракетка компьютера — за шариком. Для


ракетки игрока мы также добавили ограничение на максимальное и минимальное
значение координаты x, чтобы она не пыталась выскочить за пределы игрового поля.

Вся суть игры заключается в отбивании шарика ракетками, поэтому нужно организовать
проверку столкновений шарика с ракетками. К счастью, в Фазере уже есть
соответствующий функционал, поэтому нам достаточно его использовать.
Допишем следующие три строки в конец update():
//Проверяем и обрабатываем столкновения мячика и ракеток
game.physics.collide(ball, playerBet, ballHitsBet, null, this);
game.physics.collide(ball, computerBet, ballHitsBet, null, this);

Метод collide проверяет столкновение двух объектов (первые два параметра) и


вызывает указанную в третьем функцию для выполнения каких-либо действий над
столкнувшимися спрайтами. Эта функция выглядит так:
function ballHitsBet (_ball, _bet) {
var diff = 0;

if (_ball.x < _bet.x) {


// Шарик находится с левой стороны ракетки
diff = _bet.x - _ball.x;
_ball.body.velocity.x = (-10 * diff);
}
else if (_ball.x > _bet.x) {
// Шарик находится с правой стороны ракетки
diff = _ball.x -_bet.x;
_ball.body.velocity.x = (10 * diff);
}
else {
// Шарик попал в центр ракетки, добавляем немножко трагической
случайности его движению
_ball.body.velocity.x = 2 + Math.random() * 8;
}
}

При столкновении шарик меняет направление своего движения в зависимости от того, на


какую часть ракетки попадает.

Осталось только добавить проверку на пропущенный гол. Если кто-то его пропустил,
ставим шарик в изначальную позицию по центру поля.
function checkGoal() {
if (ball.y < 15) {
setBall();
} else if (ball.y > 625) {
setBall();
}
}

function setBall() {
if (ballReleased) {
ball.x = game.world.centerX;
ball.y = game.world.centerY;
ball.body.velocity.x = 0;
ball.body.velocity.y = 0;
ballReleased = false;
}

checkGoal() вызывается постоянно, поэтому копируем ее в конец update():

//Проверяем, не забил ли кто-то гол


checkGoal();

Все! Открываем браузер, наслаждаемся фантастическим и современным геймплеем


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

Естественно, игре не хватает еще многого, как минимум подсчета очков и определения
победителей. Но мне кажется, что для введения в разработку с Phaser достаточно
показанных вещей. Движок поддерживает много других классных функций, которые я
собираюсь показать на примере новой игры, чуть более сложной и непосредственно
относящейся к Хабру, чтобы было интереснее.
Стей тьюнед.

В ходе разработки я активно использовал код из примера breakout.php. Кроме этого


примера, в папке с Фазером есть и другие игры, поэтому тем, кому не терпится
использовать новый фреймворк, рекомендую в первую очередь посмотреть на
содержимое папки examples.

Полезные ссылки:
1. Англоязычное введение в Фазер
2. Форум, посвященный движку
3. Твиттер Ричарда Дейви

Update: по совету товарища hell0w0rd закинул пример на гитхаб и создал страничку,


чтобы можно было опробовать игру:
https://github.com/nononononono/phaser-pong
http://nononononono.github.io/phaser-pong/

Update от 20.10.2013: fessnecro добавил частицы при столкновении шарика с ракетками и


новые уровни, за что ему спасибо. Эти изменения находятся в основном бренче.
Оригинальная версия, описанная в статье, находится в ветке gh-pages.

И, на всякий случай, полный исходный код index.html: