现在的位置: 首页 > 综合 > 正文

基于HTML5/Javascrip的游戏开发框架Phaser

2016年02月27日 ⁄ 综合 ⁄ 共 6285字 ⁄ 字号 评论关闭

基于HTML5/Javascrip的游戏开发框架Phaser

申请达人,去除赞助商链接

Phaser是一个开源的HTML5游戏框架,也就是传说中100行代码之内搞定Flappy Bird的神器,通过这个框架我们可以很容易地开发桌面和移动的小游戏。目前Phaser的最新版本是2.0.7,它同时支持WebGL和Canvas。像其它游戏框架一样,Phaser封装了很多游戏开发的特性。在这篇文章中我们将会通过Phaser创建一个简单的游戏。为了专注于对框架学习,在下文中我们不会用到Phaser的任何对象,如精灵和组。

搭建Phaser

Phaser是一个通过Yeoman构建的开源的框架,我们可以在Github上下载到最新的Phaser,下载之后通过以下命令搭建:

  1. npm install -g generator-phaser-official
  2. yo phaser-official

Phaser框架的文件结构

一个Phaser工程将会有如下的文件结构:

|-- 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

Main.js作为程序入口,开始游戏。app.js用来定义一个Phaser应用,prefabs文件夹存放游戏对象,states文件夹用来保存游戏状态。 

如果你想要在这些文件中引入纯脚本,我推荐你用RequireJS或是Browserify。

Phaser.state

Phaser state将会封装游戏中不同的状态,比如游戏的加载、主菜单、级别、帮助、暂停等等……当一个state开始的时候,你可以创建与这个state相关的对象,同时你也可以在不同的state之间切换,Phaser将会为你清理过时的游戏对象,你可以在新的state中继续创建游戏对象并显示它们。

你可以通过实现预设方法来创建状态,下面我举一些重要的例子:

  • init – 当state开始的时候执行的方法,它传递一个参数使state之间共享数据。
  • preload – 当state开始的时候执行的方法,它的作用是在游戏开始前加载所有的资源文件。
  • create – preload方法执行后开始执行的方法,用来创建游戏对象。
  • shutdown – 当一个state结束的时候执行的方法,用来清理过时的游戏对象。 

State执行流程

下图是state的执行流程。Boot和Preload状态用来配置和加载游戏资源,MainMenu状态用来显示主菜单。其他的level状态是为了解决游戏过程中不同的级别和关数,每一个级别可以分成很多关,通过后进入下一关。

Game State

Boot state在preload的hook方法中加载预加载资源,并构建游戏的配置,如窗口缩放和输入内容。

File: states/boot.js

  1. function Boot() {};
  2. Boot.prototype = {
  3. preload: function() {
  4. // load preloader assets
  5. },
  6. create: function() {
  7. // setup game environment
  8. // scale, input etc..
  9. this.game.state.start('preload');
  10. }
  11. };

 Preload state加载所有的游戏资源,然后切换到main-intro状态。

File: states/preload.js

  1. Preload.prototype = {
  2. preload: function() {
  3. // load all game assets
  4. // images, spritesheets, atlases, audio etc..
  5. },
  6. create: function() {
  7. this.game.state.start('main-intro');
  8. }
  9. };

MainIntro state 用来显示游戏的介绍、logo、用户信息等等……它不需要preload方法,执行完之后就会转换到main-menu状态。

File: states/main_intro.js

  1. function MainIntroState() {};
  2. MainIntroState.prototype = {
  3. create: function() {
  4. // add main intro assets into the world
  5. this.tweenFadeState();
  6. },
  7. tweenFadeState: function() {
  8. this.game.add.tween({})
  9. .to({alpha: 1}, 2000)
  10. .onComplete.add(function() {
  11. this.game.state.start('main-menu');
  12. }, this);
  13. }
  14. };

 MainMenu state显示游戏的主界面,用户可以通过主菜单和程序进行交互。为了简单的演示,我在以下代码中添加了一个键盘触发事件,事件触发后转换到level-master状态。

File: states/main_menu.js

  1. MainMenuState.prototype = {
  2. create: function() {
  3. this.enterKey = this.game.input.keyboard
  4. .addKey(Phaser.Keyboard.ENTER);
  5. this.enterKey.onDown.add(this.tweenPlayState, this);
  6. },
  7. tweenPlayState: function() {
  8. var tweenMenuShrink = this.game.add.tween({})
  9. .to({x: 0, y: 0}, 200);
  10. var tweenFadeIn = this.game.add.tween({})
  11. .to({alpha: 1}, 2000);
  12. tweenFadeIn.onComplete.add(function() {
  13. this.game.state.start('level-master');
  14. }, this);
  15. tweenMenuShrink.chain(tweenFadeIn);
  16. tweenMenuShrink.start();
  17. }
  18. };

这里为了演示简化了tween操作,在正常的开发中,你应该在create方法中创建游戏对象,具体的创建方法可以参见Phaser的Demo和文档。

LevelMaster state在游戏界面上不显示任何的内容,它要做的只是决定选择转换到level-round state还是leverl-intro state,同时,它也会在不同的state之间更新和传递游戏数据。

File: state/level_master.js

  1. LevelMasterState.prototype = {
  2. init: function(levelData) {
  3. if (!levelData) {
  4. levelData = {
  5. level: 0,
  6. round: 1,
  7. players: [
  8. { score: 0, skill: 1 },
  9. { score: 0, skill: 1 }
  10. ]
  11. };
  12. }
  13. this.levelData = levelData;
  14. this.winScore = 2;
  15. },
  16. create: function() {
  17. this.decideLevelState();
  18. }
  19. };

当一个新的level开始,level-intro state就开始了,level-intro state会显示对这个新level的介绍,比如当前是哪种级别,在level-intro之后,会转换到level-round,也就是游戏开始的地方。

当一个round结束之后,要么是新的level,要么就是新的round。这个逻辑在decideLevelState方法中实现,如果我们通过了一个level,游戏就会进入下一个level,当已经进入最高的level之后,会切换到下一个round。

this.levelData保存游戏的数据,像当前的level、round和游戏分数。我们在这些值发生逻辑变化和切换state的时候更新它们。

File: states/level_master.js

  1. LevelMasterState.prototype = {
  2. decideLevelState: function() {
  3. if (this.isFirstLevel() || this.getWinningPlayer() !== -1) {
  4. this.nextLevel();
  5. } else {
  6. this.nextRound();
  7. }
  8. },
  9. nextLevel: function() {
  10. this.levelData.level++;
  11. this.levelData.players.forEach(function(p) {
  12. p.score = 0;
  13. }, this);
  14. this.levelData.round = 1;
  15. this.game.state.start('level-intro', true, false, this.levelData);
  16. },
  17. nextRound: function() {
  18. this.levelData.round++;
  19. this.game.state.start('level-round', true, false, this.levelData);
  20. }
  21. };

LevelIntro state显示了level的介绍信息,如你正在哪个level中。我们可以通过传递levelDate参数来保存游戏数据。在create方法中,如果用户进入第一个level,我们可以通过一个技能菜单来获取levelData,技能菜单指的是用户选择的的难度级别,这个值由你来设定。结束的时候会切换到level-round state。

File: states/level_intro.js

  1. LevelIntroState.prototype = {
  2. init: function(levelData) {
  3. this.levelData = levelData;
  4. },
  5. create: function() {
  6. var tweenIntro = this.tweenIntro();
  7. if (this.levelData.level === 1) {
  8. var tweenSkillMenuPop = this.tweenSkillMenuPop();
  9. tweenIntro.chain(tweenSkillMenuPop);
  10. tweenSkillMenuPop.onComplete.add(this.levelStart, this);
  11. } else {
  12. tweenIntro.onComplete.add(this.levelStart, this);
  13. }
  14. },
  15. levelStart: function() {
  16. this.game.state.start('level-round', true, false, this.levelData);
  17. },
  18. tweenIntro: function() {
  19. var tween = this.game.add.tween({})
  20. .to({alpha: 0}, 1000, Phaser.Easing.Linear.None, true);
  21. return tween;
  22. },
  23. tweenSkillMenuPop: function() {
  24. var tween = this.game.add.tween({})
  25. .to({x: 1, y: 1}, 500, Phaser.Easing.Linear.None, true);
  26. return tween;
  27. }
  28. };

最后LevelRound state是游戏当前所发生的位置,你可以通过update方法进行更新。为了简化演示,我在state结束的时候添加了一个点击回车键的交互事件,它会返回到lever-master,在level-master的初始位置得到传递的levelData数据。

File: states/level_round.js

  1. LevelRoundState.prototype = {
  2. init: function(levelData) {
  3. this.levelData = levelData;
  4. },
  5. create: function() {
  6. this.enterKey = this.game.input.keyboard
  7. .addKey(Phaser.Keyboard.ENTER);
  8. this.enterKey.onDown.add(this.roundEnd, this);
  9. },
  10. roundEnd: function() {
  11. this.nextRound();
  12. },
  13. nextRound: function() {
  14. this.game.state.start('level-master', true, false, this.levelData);
  15. }
  16. };

 我们已经完成了整个state的流程环,它们看起来像下面这样:

  1. Boot -> Preload ->
  2. main-intro -> main-menu ->
  3. level-master -> Level1 ->
  4. level-master -> L1 Round1 ->
  5. level-master -> L1 Round2 ->
  6. level-master -> Level2 ->
  7. level-master -> L2 Round1 ->

你可以通过在level-round state中设置一个事件转换到main-menu state来结束游戏的流程。 

开始游戏

现在我们将会运行这个Phaser游戏,将这个div放到你的页面中,Phaser将会把它的canvas放在这里。

File: index.html

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

我们需要创建一个Phaser.Game,把我们所有的state加入到StateManager中并开始Boot state。

File: app.js

  1. function Game() {}
  2. Game.prototype = {
  3. start: function() {
  4. var game = new Phaser.Game(640, 480, Phaser.AUTO, 'game-area');
  5. game.state.add('boot', BootState);
  6. game.state.add('preload', PreloadState);
  7. game.state.add('main-intro', MainIntroState);
  8. game.state.add('main-menu', MainMenuState);
  9. game.state.add('level-master', LevelMasterState);
  10. game.state.add('level-intro', MainIntroState);
  11. game.state.add('level-round', LevelRoundState);
  12. game.state.start('boot');
  13. }
  14. };

 最后,都过以下代码触发这个游戏:

File: main.js

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

 

总结

这只是利用Phaser框架开发了一个简单的游戏架子,你可以在文章上方点击下载这个Demo。同时,Phaser官方为你的开发游戏提供了很多资源,像精灵、动画、声音、物理、缩放等等,你可以访问Phaser的官网进行深入的学习

英文原文地址:http://www.sitepoint.com/javascript-game-programming-using-phaser/

抱歉!评论已关闭.