• Главная
  • О нас
  • Статьи
  • Вакансии
  • Контакты

Пишем HTML5-игру (введение в Phaser framework)

16 Октябрь 2013 by Juds in How-To, HTML5 tags: game development, HTML, JavaScript, Phaser

Эта статья посвящена разработке стильных, модных и молодежных 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:

252е

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

253e

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

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

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

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

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

255у

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

256e

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

Наконец-то все подготовительные этапы выполнены, и начинается собственно разработка. Откройте index.html и вставьте туда следующий код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">"phaser.js"</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">"text/javascript"</span>&gt;</span>
    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 () {
    }
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>

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

257e

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

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

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

Сейчас перейдем к самому интересному — наполним нашу игру логикой. После объявления переменной game и перед функцией preload() объявим объекты с ракетками игрока и компьютера, мячиком, а также укажем скорости их движения:

1
2
3
4
5
6
    var playerBet;
    var computerBet;
    var ball;
 
    var computerBetSpeed = 190;
    var ballSpeed = 300;

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

1
2
3
4
5
6
7
8
9
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(), сразу после создания фона. Ракетки будут добавлены в игру после фонового изображения, поэтому мы будем их видеть на экране:

1
2
        playerBet = createBet(game.world.centerX, 600);
        computerBet = createBet(game.world.centerX, 20);

Аналогичным образом создадим шарик, дописав следующий код сразу после вызовов функции createBet()

1
2
3
4
        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);

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

258e

 Логика

Картинка получилась симпатичной, но думаю, стоит ее слегка оживить.
Добавляем переменную, отвечающую за состояние шарика и функцию, которая будет его запускать:

1
2
3
4
5
6
7
8
9
    var ballReleased = false;
 
    function releaseBall() {
        if (!ballReleased) {
            ball.body.velocity.x = ballSpeed;
            ball.body.velocity.y = -ballSpeed;
            ballReleased = true;
        }
    }

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

1
        game.input.onDown.add(releaseBall, this);

Теперь клик мышкой запускает шарик, и он отскакивает от границ игры. Добавим движения и ракеткам, отредактировав функцию update():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function update () {
        //Управляем ракеткой игрока
        playerBet.x = game.input.x;
 
        var playerBetHalfWidth = playerBet.width / 2;
 
        if (playerBet.x <span style="color: #009900;">&lt; playerBetHalfWidth<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></span>
<span style="color: #009900;">            playerBet.x <span style="color: #66cc66;">=</span> playerBetHalfWidth;</span>
<span style="color: #009900;">        <span style="color: #66cc66;">}</span></span>
<span style="color: #009900;">        else if <span style="color: #66cc66;">(</span>playerBet.x &gt;</span> game.width - playerBetHalfWidth) {
            playerBet.x = game.width - playerBetHalfWidth;
        }
 
        //Управляем ракеткой компьютерного соперника
        if(computerBet.x - ball.x <span style="color: #009900;">&lt; -<span style="color: #cc66cc;">15</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></span>
<span style="color: #009900;">            computerBet.body.velocity.x <span style="color: #66cc66;">=</span> computerBetSpeed;</span>
<span style="color: #009900;">        <span style="color: #66cc66;">}</span></span>
<span style="color: #009900;">        else if<span style="color: #66cc66;">(</span>computerBet.x - ball.x &gt;</span> 15) {
            computerBet.body.velocity.x = -computerBetSpeed;
        }
        else {
            computerBet.body.velocity.x = 0;
        }
    }

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

Вся суть игры заключается в отбивании шарика ракетками, поэтому нужно организовать проверку столкновений шарика с ракетками. К счастью, в Фазере уже есть соответствующий функционал, поэтому нам достаточно его использовать.
Допишем следующие три строки в конец update():

1
2
3
        //Проверяем и обрабатываем столкновения мячика и ракеток
        game.physics.collide(ball, playerBet, ballHitsBet, null, this);
        game.physics.collide(ball, computerBet, ballHitsBet, null, this);

Метод collide проверяет столкновение двух объектов (первые два параметра) и вызывает указанную в третьем функцию для выполнения каких-либо действий над столкнувшимися спрайтами. Эта функция выглядит так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function ballHitsBet (_ball, _bet) {
        var diff = 0;
 
        if (_ball.x <span style="color: #009900;">&lt; _bet.x<span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></span>
<span style="color: #009900;">            <span style="color: #66cc66;">//</span>  Шарик находится с левой стороны ракетки</span>
<span style="color: #009900;">            diff <span style="color: #66cc66;">=</span> _bet.x - _ball.x;</span>
<span style="color: #009900;">            _ball.body.velocity.x <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">(</span>-<span style="color: #cc66cc;">10</span> * diff<span style="color: #66cc66;">)</span>;</span>
<span style="color: #009900;">        <span style="color: #66cc66;">}</span></span>
<span style="color: #009900;">        else if <span style="color: #66cc66;">(</span>_ball.x &gt;</span> _bet.x) {
            //  Шарик находится с правой стороны ракетки
            diff = _ball.x -_bet.x;
            _ball.body.velocity.x = (10 * diff);
        }
        else {
            //  Шарик попал в центр ракетки, добавляем немножко трагической случайности его движению
            _ball.body.velocity.x = 2 + Math.random() * 8;
        }
    }

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  function checkGoal() {
        if (ball.y <span style="color: #009900;">&lt; <span style="color: #cc66cc;">15</span><span style="color: #66cc66;">)</span> <span style="color: #66cc66;">{</span></span>
<span style="color: #009900;">            setBall<span style="color: #66cc66;">(</span><span style="color: #66cc66;">)</span>;</span>
<span style="color: #009900;">        <span style="color: #66cc66;">}</span> else if <span style="color: #66cc66;">(</span>ball.y &gt;</span> 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():

1
2
        //Проверяем, не забил ли кто-то гол
        checkGoal();

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

Заключение

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

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

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

Update: по совету товарища hell0w0rd закинул пример на гитхаб и создал страничку, чтобы можно было опробовать игру:
https://github.com/nononononono/phaser-pong
http://nononononono.github.io/phaser-pong/

И, на всякий случай, полный исходный код source
Источник: habrahabr.ru
Обучение Python. Урок 2
Обучение Python. Урок 3. Функции

Leave a Comment! Отменить ответ

You must be logged in to post a comment.
Уроки
  • Cinema 4D
  • Unity3D
  • PHP
  • Delphi
  • JavaScript
  • Python
  • HTML5
  • Go
Статьи
  • Новости
  • Game Development
  • PHP
  • QA
  • IT Юмор
  • Разное
Теги
Android Composer Delphi excerption experience Game Design game development gameplay Git Go! AOP google Google Analytics HHVM it experience it юмор Laravel Linux manager Phalcon PHP Python QA RFC Selenium Silex Slim Symfony 2 unity3d warcraft Yii Yii 2 Zend Framework 2 Zephir Биографии Новости Обучение веб-разработка высоконагруженные проекты дайджест дизайн исследование подборка ссылки стартап тенденции
О Нас

Juds–компания по разработке программного обеспечения, разработке веб-проектов и мобильных приложений. Все предлагаемые нами решения индивидуальны и направлены на максимально точное удовлетворение потребностей наших партнеров. Мы находимся в постоянном поиске новых ярких решений. Главные критерии – актуальность применения и инновационность.

Статьи
  • Лучшее из мира PHP за 2013
  • Полезные функции Google Analytics
  • Что в SEO можно считать нормальным и работающим, а что – отжившим
  • 30 полезных для себя вещей
  • Дайджест интересных новостей и материалов из мира PHP (20 октября — 10 ноября 2013)
  • Cinema 4D: создаем плагин – объект
IT Юмор
Метки
Android Composer experience Game Design game development google HHVM it experience it юмор Laravel manager PHP unity3d Yii Zend Framework 2 Zephir Новости Обучение веб-разработка дайджест исследование подборка ссылки стартап тенденции
© 2014 Juds. Все права защищены.