Статьи

Программирование игр на JavaScript с использованием Phaser

Phaser — это игровая среда HTML5 для настольных и мобильных устройств. Это быстро, бесплатно и с открытым исходным кодом. Phaser в настоящее время находится в версии 2.0.7 . Он поддерживает как WebGL, так и Canvas. Он имеет множество функций, которые помогут вам в разработке игр. Это похоже на игровую инфраструктуру Flixel для ActionScript 3. В этой статье мы Phaser.State игровой скелет с помощью Phaser, используя Phaser.State . Для простоты мы не будем использовать игровые объекты Phaser, такие как спрайты или группы. Я также немного упомяну о подростках.

Установка Phaser

Phaser доступен через bower с помощью следующей команды:

 bower install phaser-official --save 

Кроме того, вы можете получить файлы непосредственно из GitHub . Полная версия Phaser находится в каталоге build . Есть также настраиваемые сборки, такие как Phaser без физического движка, расположенные в каталоге build/custom .

Есть много уроков и руководств по началу работы. Я предлагаю вам ознакомиться с некоторыми из них, чтобы познакомиться с Phaser. Один из моих любимых — серия из четырех частей о Flappy Bird . Обширная коллекция учебных пособий, примеров и документации доступна на официальном сайте Phaser .

Леса Фазер

Генератор Yeoman на базе Grunt для Phaser доступен для строительных лесов. Вы можете установить его с помощью следующих команд:

 npm install -g generator-phaser-official yo phaser-official 

Этот генератор отлично подходит для быстрой настройки и запуска, однако для целей данного руководства мы начнем с нуля.

Структура каталога Phaser

Наш проект Phaser будет использовать структуру каталогов, показанную ниже. main.js запускает игру, а app.js определяет наше приложение Phaser. Каталог prefabs предназначен для ваших игровых объектов, а каталог states — для ваших игровых состояний.

 |-- app.js |-- main.js |-- prefabs `-- states |-- boot.js |-- level_intro.js |-- level_master.js |-- level_round.js |-- main_intro.js |-- main_menu.js `-- preload.js 

Вы должны обратить внимание на порядок включения этих файлов, если вы включаете их с простыми тегами script . Я предпочитаю использовать RequireJS, другой альтернативой является Browserify.

Phaser.State

В этом разделе основное внимание будет уделено использованию Phaser.State . Состояние Phaser заключает в себе различные состояния вашей игры. Примерами состояний игры являются предварительная загрузка, главное меню, уровень 1, уровень 2, помощь, пауза и т. Д. Когда состояние начинается, вы создаете игровые объекты, соответствующие этому состоянию. Позже вы можете переключиться в другое состояние, и Phaser очистит ваши старые игровые объекты, чтобы вы могли создавать новые игровые объекты и отображать их.

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

  • init — метод, вызываемый при запуске состояния. Передается аргумент, позволяющий обмениваться данными между состояниями.
  • preload — метод, вызываемый при начале состояния. Он используется для загрузки активов прежде всего.
  • create — метод, вызываемый после preload , используемый для создания игровых объектов.
  • update — метод, вызываемый для каждого кадра, который используется для опроса пользователей и обнаружения коллизий.
  • shutdown — метод, вызываемый при выключении состояния, который используется для очистки игровых объектов.

Организационный поток государства

Это диаграмма состояний для наших состояний фазера. Состояния Boot и Preload являются состояниями defacto для настройки конфигурации и загрузки игровых ресурсов. Состояние MainMenu предназначено для отображения главного меню. Другие состояния уровней предназначены для реального игрового процесса и переключения между различными уровнями и раундами. Уровни разбиты на раунды. Каждый уровень имеет несколько раундов, которые после игры позволяют перейти на следующий уровень.

Состояния игры Phaser

Состояния игры

Состояние загрузки загружает ресурсы предварительного загрузчика в методе ловушки preload и устанавливает параметры игры Phaser, такие как масштабирование и указатели ввода, через метод create .

File: states/boot.js

 function Boot() {}; Boot.prototype = { preload: function() { // load preloader assets }, create: function() { // setup game environment // scale, input etc.. this.game.state.start('preload'); } }; 

Состояние Preload загружает все игровые активы, а затем переключается в состояние main-intro .

File: states/preload.js

 Preload.prototype = { preload: function() { // load all game assets // images, spritesheets, atlases, audio etc.. }, create: function() { this.game.state.start('main-intro'); } }; 

Состояние MainIntro отображает вступление в игру, логотипы, кредиты и т. Д. Для этого не требуется метод preload , поскольку он настраивает объект на две секунды, а затем переключается в состояние main-menu . Я добавил здесь анимацию, просто чтобы дать вам представление о том, что вы можете анимировать свои объекты, используя такие эффекты, как затухание, сжатие и скольжение для эффектов перехода между состояниями.

File: states/main_intro.js

 function MainIntroState() {}; MainIntroState.prototype = { create: function() { // add main intro assets into the world this.tweenFadeState(); }, tweenFadeState: function() { this.game.add.tween({}) .to({alpha: 1}, 2000) .onComplete.add(function() { this.game.state.start('main-menu'); }, this); } }; 

Состояние MainMenu отображает главное меню. Затем пользователь может взаимодействовать с элементами из меню. Для простоты я добавил одно событие клавиатуры, которое вызовет цепочку анимации и в конце переключится в состояние level-master . Цепочка анимации полезна для комбинированных анимаций, таких как сжатие меню и затемнение экрана.

File: states/main_menu.js

 MainMenuState.prototype = { create: function() { this.enterKey = this.game.input.keyboard .addKey(Phaser.Keyboard.ENTER); this.enterKey.onDown.add(this.tweenPlayState, this); }, tweenPlayState: function() { var tweenMenuShrink = this.game.add.tween({}) .to({x: 0, y: 0}, 200); var tweenFadeIn = this.game.add.tween({}) .to({alpha: 1}, 2000); tweenFadeIn.onComplete.add(function() { this.game.state.start('level-master'); }, this); tweenMenuShrink.chain(tweenFadeIn); tweenMenuShrink.start(); } }; 

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

Состояние LevelMaster — это безголовое состояние, которое решает, в какое состояние переключаться. Он ничего не отображает в игровом мире. Его единственная цель состоит в том, чтобы решить, должен ли он переключаться в состояние level-round или состояние level-intro , и, самое главное, он обновляет и передает игровые данные ( this.levelData ) между состояниями.

File: states/level_master.js

 LevelMasterState.prototype = { init: function(levelData) { if (!levelData) { levelData = { level: 0, round: 1, players: [ { score: 0, skill: 1 }, { score: 0, skill: 1 } ] }; } this.levelData = levelData; this.winScore = 2; }, create: function() { this.decideLevelState(); } }; 

Когда начинается новый уровень, начинается состояние level-intro . Состояние level-intro отображает вступление на новый уровень, например, показывает, на каком уровне вы находитесь. После level-intro , он переключается на level-round , где происходит реальный игровой процесс.

После окончания раунда это либо новый level-round либо новый уровень. Эта логика происходит в нашей функции decideLevelState . Если это первый уровень или у нас есть победитель уровня, мы переключаемся на следующий уровень, в противном случае мы переключаемся на следующий раунд.

this.levelData содержит данные игры, такие как уровень игры, раунд игры и результаты игрока. Мы обновляем это в нашей логике и передаем состояния.

File: states/level_master.js

 LevelMasterState.prototype = { decideLevelState: function() { if (this.isFirstLevel() || this.getWinningPlayer() !== -1) { this.nextLevel(); } else { this.nextRound(); } }, nextLevel: function() { this.levelData.level++; this.levelData.players.forEach(function(p) { p.score = 0; }, this); this.levelData.round = 1; this.game.state.start('level-intro', true, false, this.levelData); }, nextRound: function() { this.levelData.round++; this.game.state.start('level-round', true, false, this.levelData); } }; 

Состояние LevelIntro отображает информацию о введении уровня, такую ​​как уровень, на котором вы находитесь, и некоторую анимацию вступления. Мы levelData параметр levelData , который содержит данные игры. В методе create мы используем levelData , отображая меню навыков, если это первый уровень игры. Под меню навыков я подразумеваю меню, в котором игрок выбирает, какой навык он хочет использовать, но решать вам. В конце он переключается в состояние level-round .

File: states/level_intro.js

 LevelIntroState.prototype = { init: function(levelData) { this.levelData = levelData; }, create: function() { var tweenIntro = this.tweenIntro(); if (this.levelData.level === 1) { var tweenSkillMenuPop = this.tweenSkillMenuPop(); tweenIntro.chain(tweenSkillMenuPop); tweenSkillMenuPop.onComplete.add(this.levelStart, this); } else { tweenIntro.onComplete.add(this.levelStart, this); } }, levelStart: function() { this.game.state.start('level-round', true, false, this.levelData); }, tweenIntro: function() { var tween = this.game.add.tween({}) .to({alpha: 0}, 1000, Phaser.Easing.Linear.None, true); return tween; }, tweenSkillMenuPop: function() { var tween = this.game.add.tween({}) .to({x: 1, y: 1}, 500, Phaser.Easing.Linear.None, true); return tween; } }; 

Наконец, состояние LevelRound — это место, где происходит фактическая игра. Вы можете использовать его метод update если вам нужно. Для простоты я добавил простое взаимодействие клавиш, которое завершает состояние при нажатии Enter. Важным примечанием здесь является то, что он переключается обратно на level-master , передавая данные levelData , полученные в первую очередь от level-master .

File: states/level_round.js

 LevelRoundState.prototype = { init: function(levelData) { this.levelData = levelData; }, create: function() { this.enterKey = this.game.input.keyboard .addKey(Phaser.Keyboard.ENTER); this.enterKey.onDown.add(this.roundEnd, this); }, roundEnd: function() { this.nextRound(); }, nextRound: function() { this.game.state.start('level-master', true, false, this.levelData); } }; 

Это завершает наш государственный поток. Все это предоставляет нам цикл состояния уровня, который выглядит примерно так:

 Boot -> Preload -> main-intro -> main-menu -> level-master -> Level1 -> level-master -> L1 Round1 -> level-master -> L1 Round2 -> level-master -> Level2 -> level-master -> L2 Round1 -> 

Вы можете выйти из этого цикла в состоянии level-round с помощью действия, которое переключается в состояние main-menu .

Фазер запуска

Теперь мы запустим игру Phaser. Поместите этот div внутри вашей страницы. Фазер разместит там свой холст.

File index.html

 <div id="game-area"></div> 

Мы должны создать Phaser.Game , добавить все наши состояния в StateManager и запустить состояние загрузки.

File: app.js

 function Game() {} Game.prototype = { start: function() { var game = new Phaser.Game(640, 480, Phaser.AUTO, 'game-area'); game.state.add('boot', BootState); game.state.add('preload', PreloadState); game.state.add('main-intro', MainIntroState); game.state.add('main-menu', MainMenuState); game.state.add('level-master', LevelMasterState); game.state.add('level-intro', MainIntroState); game.state.add('level-round', LevelRoundState); game.state.start('boot'); } }; 

Наконец, запустите игру, используя следующий код.

File: main.js

 var game = new Game(); game.start(); 

Вывод

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