这篇文章由Alvin Ourrad 和 Richard Davey所著。

已更新使用Phaser 2.0版本。

欢迎来到我们的第一篇关于使用Phaser制作一个游戏的教程。这里我们将学习如何制作一个关于角色在平台间奔跑跳跃收集星星的小游戏。在整个制作流程间我们会解释Phaser框架的一些核心特性。

Phaser是什么?

Phaser是一个HTML5游戏框架,致力于帮助开发者快速制作强大的跨浏览器HTML5游戏。不像有些框架,Phaser已完全调配手机浏览器。Phaser唯一的浏览器要求是支持canvas标签。Phaser也从Flixel借鉴很多东西。

要求

  • 下载教程匹配的源文件和资产。
  • 你应该具有非常非常基础的JavaScript知识。
  • 确保你浏览了入门指南,它会向你说明如何下载框架,如何搭建一个本地开发环境,让你一窥Phaser的项目结构和核心功能。

如果你已经浏览了入门指南你应该已经下载了Phaser,一切已经准备就绪就等着编写代码了。下载本教程的资源然后把它解压到你的本地web服务器根目录。

在你选择的文本编辑器打开part1.html网页,让我们仔细看看代码。在包含Phaser的样板HTML后面的代码结构如下:

[javascript] view plain copy print ?
  1. var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update });
  2. function preload() {
  3. }
  4. function create() {
  5. }
  6. function update() {
  7. }

第一行你创建了一个Phaser.Game对象的实例并赋值给本地变量game,以此来激活Phaser。把它叫做game是惯例,但不是必需的,你会在Phaser的示例里发现这种作法。

前两个参数是Phaser要创建的canvas元素的宽高。这里是800 x 600像素。这个是游戏要显示的分辨率,你的游戏世界则可以是任意你喜欢的尺寸。第三个参数可以是Phaser.CANVAS,Phaser.WEBGL,或Phaser.AUTO。这个是你想使用的渲染上下文。推荐的参数是Phaser.AUTO,它会自动尝试使用WebGL,如果浏览器或设备不支持它就会回滚成Canvas。

第四个参数是一个空字符串,这个是你想插入Phaser创建的canvas元素的DOM元素的id。因为我们把它放空,canvas元素会简单地被附加到body。最后一个参数是一个包含四个Phaser基本函数引用的对象。它们的用法在这里被详细解释。注意这个对象不是必需的——Phaser支持一个完整的状态系统,允许你把你的代码分散到几个非常简洁的单一对象。对于这篇入门指南,我们使用这个方法有助于快速构建原型。

加载资产

让我们加载我们游戏需要的资产。你通过在preload函数里调用game.load来完成这个。Phaser在它启动时会搜寻这个函数并加载任何在其中被定义的资产。

当前preload函数是空的。把它变成这样:

[javascript] view plain copy print ?
  1. function preload() {
  2. game.load.image('sky', 'assets/sky.png');
  3. game.load.image('ground', 'assets/platform.png');
  4. game.load.image('star', 'assets/star.png');
  5. game.load.spritesheet('dude', 'assets/dude.png', 32, 48);
  6. }

它会加载四个资产:三张图片和一张精灵图。对于你们中的有些人这可能看起来很显然,但是我想说明下第一个参数,又称为资产的键。这个字符串是已加载资产的链接,当你创建子图形时会用到。对于资产的键你可以随意使用任何合法的JavaScript字符串。

创建一张子图形

为了添加一张子图形到我们的游戏,放置以下代码到create函数里:

[javascript] view plain copy print ?
  1. game.add.sprite(0, 0, 'star');

如果你在浏览器里查看这个网页你应该会看到一个黑色的游戏场景,在左上角有一个单一星星的子图形。

显示的项的渲染顺序匹配你创建它们的顺序。所以如果你希望把背景放置在星星子图形的下面你应该确保背景早于星星被添加。

世界建立

game.add.sprite在内部创建一个新的Phaser.Sprite对象然后把它添加到游戏世界。这个世界就是你的所有对象所在之地,和Actionscript3的Stage差不多。

注意:这个游戏世界没有固定的尺寸,在所有方向无限延伸,(0,0)坐标是它的中心。为了你的方便Phaser把(0,0)放置在你的游戏的左上角,但是通过内建的摄像机你可以根据需求进行移动。

世界类可以通过game.world获取,它带来了很多便利的方法和属性,以帮助你在世界里分发你的物体。它包含一些简单的属性像game.world.height,但是也包含一些更高级的东西,我们会在另一个教程里用到。

现在让我们通过添加一个背景和一些平台来搭建场景。更新后的create函数如下:

[javascript] view plain copy print ?
  1. var platforms;
  2. function create() {
  3. //  We're going to be using physics, so enable the Arcade Physics system
  4. game.physics.startSystem(Phaser.Physics.ARCADE);
  5. //  A simple background for our game
  6. game.add.sprite(0, 0, 'sky');
  7. //  The platforms group contains the ground and the 2 ledges we can jump on
  8. platforms = game.add.group();
  9. //  We will enable physics for any object that is created in this group
  10. platforms.enableBody = true;
  11. // Here we create the ground.
  12. var ground = platforms.create(0, game.world.height - 64, 'ground');
  13. //  Scale it to fit the width of the game (the original sprite is 400x32 in size)
  14. ground.scale.setTo(2, 2);
  15. //  This stops it from falling away when you jump on it
  16. ground.body.immovable = true;
  17. //  Now let's create two ledges
  18. var ledge = platforms.create(400, 400, 'ground');
  19. ledge.body.immovable = true;
  20. ledge = platforms.create(-150, 250, 'ground');
  21. ledge.body.immovable = true;
  22. }

如果你运行part4.html,你会看见一个更像游戏的场景:

第一部分和我们之前的星星子图形一样,只是我们把键替换成sky,最终显示一张天空背景而不是一颗星星。这是一张填充了整个游戏屏幕的800×600的PNG图片。

组很强大。正如它们的名字,组允许你集合简单的对象然后把它们当做一个单一单元进行控制。你也能在不同组间检测碰撞。这个游戏我们将使用两个不同的组,其中一个是上面代码创建的平台组。

[javascript] view plain copy print ?
  1. platforms = game.add.group();

正如子图形,game.add方法创建我们的组对象。我们把它赋值给一个新的本地变量platforms。创建组后,现在我们可以给它添加物体。首先是地面ground。它被放置到游戏的底部,使用了之前加载的ground图片。地面被缩放以便填满游戏的宽。最后我们设置它的immovable属性为true。如果我们不这么做当玩家碰撞到它它会移动(细节查看Physics部分)。

当正确放置地面后我们用相同的技术创建两个更小的可供跳跃的壁架。

准备一个角色

创建一个新的本地变量player然后添加以下的代码到create函数。你能在part5.html看到:

[javascript] view plain copy print ?
  1. // The player and its settings
  2. player = game.add.sprite(32, game.world.height - 150, 'dude');
  3. //  We need to enable physics on the player
  4. game.physics.arcade.enable(player);
  5. //  Player physics properties. Give the little guy a slight bounce.
  6. player.body.bounce.y = 0.2;
  7. player.body.gravity.y = 300;
  8. player.body.collideWorldBounds = true;
  9. //  Our two animations, walking left and right.
  10. player.animations.add('left', [0, 1, 2, 3], 10, true);
  11. player.animations.add('right', [5, 6, 7, 8], 10, true);

这个创建一个新的子图形称作player,放置在x轴32像素,从游戏底部向上150像素的地方。我们指定它使用之前加载的dude资产。如果你回到preload函数看看你会看到dude被加载为精灵图,而非图片。这是因为它包含动画帧。整个精灵图看起来像这样:

你能看到一共9帧,4帧向左跑,1帧面朝摄像机,4帧向右跑。注意:Phaser支持翻转子图形来节省动画帧,但是作为入门教程我们使用守旧的方法。我们定义两个动画left和right。letf动画使用了0,1,2,3帧并且以10帧每秒的速度播放。true参数指定动画循环播放。这就是我们标准的奔跑循环动画,我们在相反的方向再重复一遍。动画设置完后我们创建一些物理属性。

实体和速度:物理世界

Phaser已支持一些不同的物理系统,载有Arcade Physics,,Ninja Physics 和 P2.JS Full-Body Physics。出于教程目的我们将使用Arcade物理系统,一个对手机浏览器而言简单轻量高效的物理系统。你会注意到我们不得不先启动物理系统,然后再启用每个我们想运用物理的子图形或组。

一旦完成子图形会获得一个新的body属性,它是ArcadePhysics.Body的一个实例。这表示子图形在Phaser的Arcade物理引擎里将被当做一个物理实体。body对象拥有很多有用的属性。为了在子图形上模拟重力效果,可以简单写成:

[javascript] view plain copy print ?
  1. player.body.gravity.y = 300;

这可以是一个任意值,但是逻辑上,值越大,你的物体就越重,下落地越快。如果你添加这个到你的代码或者运行part5.html你会发现角色不停地下落,完全无视我们之前创建的地面:

原因是我们没有在地面和角色间检测碰撞。我们已经告诉Phaser我们的地面和壁架是固定不动的。如果我们不这么做当角色碰撞到它们角色会停止下落一会儿然后所有东西都会塌下。这是因为如果不指明不动,地面子图形是一个可动的物理物体(也称为动态物体),当角色撞击它,撞击力将作用于地面,这两个实体互换速度然后地面也就开始下落。

所以为了启用角色的碰撞和利用物理属性,我们需要在update函数里引入碰撞检测:

[javascript] view plain copy print ?
  1. function update() {
  2. //  Collide the player and the stars with the platforms
  3. game.physics.arcade.collide(player, platforms);
  4. }

update函数在核心游戏循环的每帧都会调用。Physics.collide函数是施展魔术的表演者。它在两个物体间检测碰撞然后将碰撞的物体分开。所以我们在角色和平台组间使用这个函数。它足够聪明能为组的所有成员启用碰撞检测,所以角色将能和地面和所有的壁架碰撞。结果就是平台变得坚固:

使用键盘控制角色

碰撞很好,但是现在我们需要让角色能移动。你可能想去文档里找找如何添加一个事件处理程序,但是这里不需要这样。Phaser内建了键盘管理器,可以使用这个便利的函数:

[javascript] view plain copy print ?
  1. cursors = game.input.keyboard.createCursorKeys();

这将给cursors对象填入四个属性:up,down,left,right,这些属性都是Phaser.Key对象的实例。接下来我们需要的就是在update循环里轮询这些:

[javascript] view plain copy print ?
  1. //  Reset the players velocity (movement)
  2. player.body.velocity.x = 0;
  3. if (cursors.left.isDown)
  4. {
  5. //  Move to the left
  6. player.body.velocity.x = -150;
  7. player.animations.play('left');
  8. }
  9. else if (cursors.right.isDown)
  10. {
  11. //  Move to the right
  12. player.body.velocity.x = 150;
  13. player.animations.play('right');
  14. }
  15. else
  16. {
  17. //  Stand still
  18. player.animations.stop();
  19. player.frame = 4;
  20. }
  21. //  Allow the player to jump if they are touching the ground.
  22. if (cursors.up.isDown && player.body.touching.down)
  23. {
  24. player.body.velocity.y = -350;
  25. }

虽然我们添加了很多代码不过它应该非常易读。我们做的第一件事是重置子图形的水平速度。然后我们检测左光标键是否被按下。如果是,我们应用一个负的水平速度然后开始播放向左奔跑的动画。如果右光标键被按下则采取相反的措施。通过在每帧清除速度然后再设置它的方法创建了停止—开始式的运动。

角色的子图形只有在一个键被按下的时候移动,没有按下则立即停止。Phaser也允许你使用动量和加速度创建更复杂的运动,但是之前的效果就是我们这个游戏需要的。键检测的最后部分就是如果没有键被按下就把帧设置为4。精灵图的第四帧就是角色看着你,没有运动。

跳跃

代码的最后部分就是添加跳的能力。上光标键就是我们的跳跃键,我们会检测它是否被按下。然而我们也要检测角色是否接触到地面,否则它们可能会在半空中跳跃。如果这些条件都满足我们会应用一个350的竖直速度。角色会自动落回地面因为我们给它应用了重力值。当控制设置好后我们得到了一个我们可以探索的游戏世界。加载part7.html然后玩一玩。尝试调整类似350能使角色跳的更高或更低的值然后看看会有什么效果。

星光

是时候给我们的小游戏一个目的。让我们在场景里撒下一些星星然后让角色去收集它们。为了完成这个目标我们会创建一个新的组stars然后填充它。在我们的create函数我们添加以下代码(详见part8.html):

[javascript] view plain copy print ?
  1. stars = game.add.group();
  2. //  Here we'll create 12 of them evenly spaced apart
  3. for (var i = 0; i < 12; i++)
  4. {
  5. //  Create a star inside of the 'stars' group
  6. var star = stars.create(i * 70, 0, 'star');
  7. //  Let gravity do its thing
  8. star.body.gravity.y = 6;
  9. //  This just gives each star a slightly random bounce value
  10. star.body.bounce.y = 0.7 + Math.random() * 0.2;
  11. }

流程和我们创建平台组的时候相似。我们使用JavaScript的for循环在游戏里创建了12颗星星。它们拥有i*70的x轴坐标,这意味着它们每隔70像素等距放置。如同角色我们给这些星星一个重力值使得它们能下落,给它们一个反弹值使得它们撞击平台后会反弹几下。反弹是一个介于0(不会反弹)到1(无消耗反弹)的值。我们会设置反弹值在0.7到0.9左右。如果我们运行了代码会发现星星跌下了游戏的底部。为了防止那样我们需要在update循环里在它们和平台间启用碰撞检测:

[javascript] view plain copy print ?
  1. game.physics.arcade.collide(stars, platforms);

同时我们也要检测星星是否和角色重叠了:

[javascript] view plain copy print ?
  1. game.physics.arcade.overlap(player, stars, collectStar, null, this);

这行代码告诉Phaser去检测角色和星星组里任何星星的重叠。如果发现重叠就把它们传入collectStar函数:

[javascript] view plain copy print ?
  1. function collectStar (player, star) {
  2. // Removes the star from the screen
  3. star.kill();
  4. }

很简单,当一个星星被清除就不再显示它。运行游戏,现在我们的角色可以左冲右撞,可以跳跃,可以从平台上反弹和收集从天而降的星星。很不错只用了很少的几行代码,大多数非常易读。

最后润色

最后的调整是添加分数。实现这个我们将使用一个Phaser.Text对象。这里我们创建两个新变量,一个保存着实际的分数一个是文本对象本身:

[javascript] view plain copy print ?
  1. var score = 0;
  2. var scoreText;

scoreText在create函数里赋值:

[javascript] view plain copy print ?
  1. scoreText = game.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });

16×16是文本显示位置的坐标。score 0是默认显示的字符串,最后一个对象包含了字体尺寸和填充颜色。没有指定字体我们实际上使用了浏览器的默认字体,在Windows系统是Arial。接下来我们需要修改collectStar函数,以便当角色拾起一颗星星分数会增加而文本会更新以反映分数:

[javascript] view plain copy print ?
  1. function collectStar (player, star) {
  2. // Removes the star from the screen
  3. star.kill();
  4. //  Add and update the score
  5. score += 10;
  6. scoreText.content = 'Score: ' + score;
  7. }

所以每颗星星十分,scoreText会更新以显示新分数。如果你运行part9.html你会看到最终的游戏:

结尾

你现在学习了如何创建一个带有物理属性的子图形,如何控制它的运动,如何使它和一个小游戏世界里的其它物体交互。还有很多东西你可以去增强这个游戏,比如说它没有结束或惩罚的概念。为什么不添加一些你必须躲避的钉子?你可以创建一个新的钉子组然后让它和角色检测碰撞,只是这次碰撞将杀死角色而不是钉子。或者做一个非暴力的游戏,你必须快速移动,挑战在尽可能短的时间内收集所有的星星。我们已经在压缩包里放置了额外的图形以帮助激发你的灵感。

在你学习了这篇教程和这250+个例子后,你应该对未来的工程有一个结实的基础。但是只要你有疑问,需要建议或者想分享,随意来Phaser forum。

笔者注

讲的很基础,很详细,演示地址http://www.sunnylinner.com/stars/

phaser入门教程相关推荐

  1. Kafka入门教程与详解

    1 Kafka入门教程 1.1 消息队列(Message Queue) Message Queue消息传送系统提供传送服务.消息传送依赖于大量支持组件,这些组件负责处理连接服务.消息的路由和传送.持久 ...

  2. 【CV】Pytorch一小时入门教程-代码详解

    目录 一.关键部分代码分解 1.定义网络 2.损失函数(代价函数) 3.更新权值 二.训练完整的分类器 1.数据处理 2. 训练模型(代码详解) CPU训练 GPU训练 CPU版本与GPU版本代码区别 ...

  3. python tornado教程_Tornado 简单入门教程(零)——准备工作

    前言: 这两天在学着用Python + Tornado +MongoDB来做Web开发(哈哈哈这个词好高端).学的过程中查阅了无数资料,也收获了一些经验,所以希望总结出一份简易入门教程供初学者参考.完 ...

  4. python向量计算库教程_NumPy库入门教程:基础知识总结

    原标题:NumPy库入门教程:基础知识总结 视学算法 | 作者 知乎专栏 | 来源 numpy可以说是 Python运用于人工智能和科学计算的一个重要基础,近段时间恰好学习了numpy,pandas, ...

  5. mysql query browswer_MySQL数据库新特性之存储过程入门教程

    MySQL数据库新特性之存储过程入门教程 在MySQL 5中,终于引入了存储过程这一新特性,这将大大增强MYSQL的数据库处理能力.在本文中将指导读者快速掌握MySQL 5的存储过程的基本知识,带领用 ...

  6. python tensorflow教程_TensorFlow入门教程TensorFlow 基本使用T

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 TensorFlow入门教程 TensorFlow 基本使用 TensorFlow官方中文教程 TensorFlow 的特点: 使用图 (graph) 来 ...

  7. air调用java,AIR2.0入门教程:与Java应用交互

    在之前的一篇文章中,我介绍了如何使用AIR2.0新增的NativeProcess类与本地进程进行交互和通讯,在那个例子里面我们使用了C++ 的代码,实际上只要是基于命令行的标准输入输出,AIR2.0的 ...

  8. 【Arduino】开发入门教程【一】什么是Arduino

    Arduino Arduino 是一款便捷灵活.方便上手的开源电子原型平台,包含硬件(各种型号的arduino板)和软件(arduino IDE).它适用于艺术家.设计师.爱好者和对于"互动 ...

  9. python 三分钟入门_Cython 三分钟入门教程

    作者:perrygeo 译者:赖勇浩(http://laiyonghao.com) 原文:http://www.perrygeo.net/wordpress/?p=116 我最喜欢的是Python,它 ...

最新文章

  1. 异步调用可以转化为同步调用吗?
  2. Linux 64位 CentOS下安装 Docker 容器,启动、停止
  3. ldd随笔(1)-linux设备模型
  4. javafx swing_Swing应用程序中的JavaFX 8 DatePicker
  5. “黑天鹅”,正在改变 AI 落地医疗领域的加速度
  6. android.os文件,使用android.os.memoryfile的文件IO
  7. TypeError: '' not supported between instances of 'float' and 'str'
  8. python html表格模版,python-如何使用模板(例如Jinja2)将列值列表呈现到表中
  9. 通用各类数据库密码字典
  10. mysql delphi5_Delphi 7连接MySql 5.5.15
  11. 湖北省疫情数据可视化分析
  12. windows下制作iso文件,WinMount介绍
  13. word多级目录设置和自动生成目录
  14. TeamViewer设备数量受限的解决办法
  15. 搜狗浏览器屏蔽广告插件_“云法庭”里“云勘验”,海淀法院开庭审理搜狗浏览器插件屏蔽优酷视频广告不正当竞争纠纷案...
  16. c语言带进位循环左移,带进位循环左移指令.ppt
  17. flutter dart 获取当前时间戳
  18. SRM系统可以为企业带来哪些帮助?
  19. 安装Realtek HD Audio Driver 失败
  20. 新水浒传暴风影音播放清单

热门文章

  1. 中山大学2021计算机考研复试线,中山大学2021年考研复试基本分数线已发布
  2. ReactNative 在丁香医生项目中引入的踩坑日记
  3. 对图片进行膨胀与腐蚀
  4. 激光雷达主要应用在哪些领域?
  5. 2022-2028年中国AI 3D装箱拣选系统市场现状研究分析与发展前景预测报告
  6. linux中文镜像文件iso下载地址,linux系统镜像iso文件下载
  7. 计算机打字竞赛活动背景,学生打字比赛的活动策划书
  8. RFID助力环保事业护林管理
  9. python 灰度图像素灰度值求和_如何使用PIL-Numpy在Python中获取灰度图像的平均像素值?...
  10. 又改考408了!杭州师范大学阿里巴巴商学院!