您现在的位置:首页 > 游戏资讯 > 人物代码

HTML5游戏框架大军中的一乘轻骑——Phaser

来源:完美世界私服 浏览次数: 发布时间:2023-06-06 16:55:11

【编者按】HTML5游戏因其“低门槛、低成本、简单好玩、易分享”的特点而受到广大玩家的喜爱和业界的关注。 无论您是新手还是企业专业团队,从头开始制作游戏并不总是一个好主意。 选择适合自己的游戏引擎或框架才是正道。 本文将介绍HTML5游戏框架大军中的轻骑——Phaser。

移相器简介

Phaser 是由 Photon Storm 创建的开源 HTML5 游戏框架。 2011年1.0版本发布后,进入稳定期,定期更新版本。 许多新功能和修复将很快完成。 稳定版本大约每月发布一次 - 请参阅 GitHub 上的完整变更日志。 Phaser 旨在创建在桌面和移动网络浏览器上运行的游戏。 近年来,人们越来越关注移动设备上的网络浏览器的性能,以及快速增长且非常重要的网络游戏领域。 Photon Storm早在2011年就开始制作游戏工具和游戏,其技术积累可以帮助开发者提供游戏开发中的各种需求,直面游戏开发中的痛点。

Phaser 的主要特点

朴素的 JavaScript 编程风格

这听起来像是一个奇怪的“功能”,但它实际上非常有吸引力。 Phaser 内部不使用任何人为的 OO 风格编程。 没有海量的继承链和组件系统,你不必强制将对象设计成任何固定的类结构。 只有简单直接的原型链,最自然的JavaScript使用方式。

这并不意味着您不能以结构化的方式创建游戏。 这只是意味着它不是强制性的。 这也意味着 Phaser 内饰可以轻松改装。

简单易用的资源加载

Phaser 的内置资源加载器可以处理:

我通常直接从 Flash 将纹理图块集导出到 Phaser 游戏,并且完全支持修剪边距的图块集。 资产可以部分加载、缓存和从不同的 URL 中提取(用于 CDN 支持),您只需一行代码就可以将任何 sprite 变成进度条。

渲染:WebGL 和 Canvas

Phaser 内部使用 Pixi.js 进行渲染。 Pixil 是一个很棒的快速渲染库,专注于 Canvas 和 WebGL。 Photon Storm 声称将继续资助这个库的持续改进和发展。

对于您的游戏,这意味着如果浏览器支持 WebGL,那么玩家将获得更流畅的游戏体验。 WebGL 在桌面平台上已经非常普遍,但在移动平台上仍处于发展的早期阶段。 即便如此,这是 HTML5 游戏开发的未来,所以支持它非常重要。 最新的 Phaser 版本引入了 WebGL 着色器和过滤支持,即将发布的版本将实现法线贴图,因此您将能够使用 Sprite Lamp 等新工具。

音频:网络音频和传统音频

多年来,音频一直是 HTML 游戏的弱点。 仅在几年前,还存在选择单声道高延迟音频或根本没有音频的两难境地。 值得庆幸的是,时代变了,Web Audio API 来拯救我们。 它支持基于节点的音频、多通道、节点路由和各种效果。 毫无疑问,Phaser 完全支持 Web Audio。

然而,许多设备,尤其是 Android 设备,仍然不支持 Web Audio - 所以 Phaser 也支持传统音频并使用 Audio Sprites:将一组声音打包到一个文件中,然后使用播放标记跳转到不同的效果。 Phaser 将根据设备的功能以两种方式进行本地切换,还包括为您自动解锁音频系统,这已经俘获了许多第一批移动开发人员的心。

输入:多点触控,键盘,指针,鼠标

在同时支持桌面和移动平台时,有越来越多的不同潜在输入选项。 Phaser 支持键盘、鼠标、触摸、MSPointer(目前 Pointer 在 IE11 下)及其组合。 例如,在 Windows Surface 设备上,您可以在鼠标和触摸之间切换,或同时使用两者。

对于触摸输入,Phaser 可以处理单点触摸和多点触摸环境。 您最多可以定义 10 个触摸点,独立跟踪它们,并使用它们的事件来处理 sprite 交互,例如拖动、点击和碰撞。

物理、补间动画和粒子

集成到核心库中的是 ArcadePhysics 和 ArcadeParticles 系统。 它们是简单的 AABB 轻量级库,允许您对任何精灵使用重力和运动,然后测试它的碰撞和分离。 使用基于世界的四叉树有助于最大程度地减少碰撞测试,并且您可以在很短的时间内获得非常好的结果。

然而,内置的物理系统不太可能适用于所有类型的游戏,因此物理系统可以很容易地更换,并且没有绑定到实际精灵(但身体组件)的物理属性,因此可以更换通过 Box2D 或 p2.js 之类的东西。 还集成了补间系统,使您可以轻松地补间对象或属性。 如果游戏暂停,所有补间都会自动暂停并在需要时恢复。

插件系统

Phaser 的目标是最终稳定并变得稳定和平衡,它不太可能涉足修复和浏览器更新以外的主题。 同时,我希望 Phaser 不断成长,为各种游戏提供功能,但不会导致核心库爆炸。 为此,Photon Storm 构建了一个插件系统。

Phaser 插件可以在核心框架中注册自己,在核心游戏循环中更新,从而执行各种有用的额外任务。 一个很好的例子是最近发布的 Photon Storm,它会自己发布插件,但也期望将来有很多来自社区的插件。

社区评价

在知名的NK社区,活跃的开发者有很多有价值的交流和评论。

网友balazsdavid987:在尝试了几个HTML5/JS游戏框架库后,我确信Phaser是最好的2D游戏框架库。 它经常更新,具有出色的文档和出色的社区支持。 只需阅读 Phaser 的源代码,您就可以学到很多游戏开发技术。 我们在iOS上打造了一个完整的小游戏平台,在线网友dtft:都是phaser游戏。 虽然它们不是杰作,但它们速度快且具有挑战性。 我们发现 Phaser 非常适合快速开发和原型制作。

网友georgefrick:我们正在用phaser做91个应用(系列教育游戏/互动/故事书)。 进展顺利,已经完成了一半以上的申请。 虽然 Phaser 有缺陷,但任何框架都会有错误。

网友HobbesDT:Phaser对我来说非常容易上手,即使我没有太多的计算机科学经验,也可以在移动平台(至少是iOS)上不费吹灰之力就能很好地运行。 如果你不知道如何制作游戏,想快速制作一款简单的游戏,这绝对是一个很棒的框架库。 官网有非常丰富的教程和例子,也可以在第三方网站上找到很多资料。

网友GavinAnderegg:大约一年前,我和一些朋友在一个12小时的黑客马拉松中使用Phaser做了一个小游戏。 这是一个不错的小框架,虽然我们并没有真正使用它的很多功能,但它很容易上手。

您可以在此处查看我们制作的游戏。

设置开发环境

完美世界取消暂停代码

安装网络服务器

由于浏览器的一些安全机制,开发HTML5游戏最好使用iis、apache等本地web服务器。 如果直接双击打开html页面,部分功能可能无法正常使用。

建议初学者安装服务器套件包,它在单个可执行文件中包含流行的 Web 开发工具,例如 Apache、PHP 和 Mysql。 对于 Windows 平台,推荐使用 WAMP Server 或 XAMPP。 对于 OS X 平台,强烈推荐使用 MAMP。

选择编辑器

下一步是选择一个好用的编辑器来编写代码。 如果您是一位经验丰富的开发人员,我相信您已经拥有了自己喜欢的编辑器。 如果是新手,我推荐 Sublime Text。 Phaser 还支持 TypeScript,所以你也可以选择使用微软的 Visual Studio 作为编辑器。

下载移相器

Phaser 框架是开源的,源代码托管在 GitHub 上。

测试环境是否准备就绪

此时,您已经安装了 Web 服务器、设置了编辑器并下载了 Phaser。 现在是创建第一个测试项目并测试环境是否准备就绪的时候了。

导航到您的“Web 根目录”,这是 Web 服务器查找文件的文件夹。 如果你在Windows上使用WAMP,可以用鼠标左键点击系统图标中的WAMP图标,在弹出的菜单中选择“www目录”,即可在文件浏览器中打开该目录。

下载此 zip 文件。 它包含一个 hellophaser 目录,其中包含一个 JavaScript 文件、一个 index.html 和一个 PNG 文件。 将 Hellophaser 目录复制到 Web 服务器根目录。

打开 Web 浏览器并浏览到本地服务器上的 Hellophaser 目录。 通常只需在浏览器中输入 localhost/hellophaser 或 127.0.0.1/hellophaser 即可。 如果一切正常,中间会出现一个黑色的游戏区域,上面有 Phaser 标志。

如果由于某种原因不正确,则需要打开调试窗口查看错误输出。 如果只是简单的文件丢失错误,请检查您的目录名称,然后刷新页面。 如果是复杂的错误,可以在Phaser社区发帖求助,会得到开发团队和热心人士的帮助。

使用 Phaser 创建您的第一款游戏

在此示例中,正在创建的游戏名为 Monsters Want Candy。 首先介绍项目的结构,以便您了解整体游戏玩法。 我们将按照游戏运行的逻辑顺序依次讲解:加载图片资源、创建主菜单、真正的游戏循环。 您可以点击链接先试玩 Monster Wants Candy。

项目设置和结构

项目目录包含 index.html 文件(包括 HTML5 结构和所有必要的 JS 文件)。 还有两个子目录:IMG目录,里面是美术资源;src目录,里面是游戏的源代码。

这是目录结构的预览:

图1 目录结构预览

在 src 目录中,您将看到 JavaScript 文件。 在本教程中,我将描述该文件夹中所有文件的内容和用途。 您可以在 GitHub 上查看每个文件的源代码。

index.html 文件

我们从 index.html 文件开始。 它看起来像一个 HTML5 网站,但没有文本和 HTML 元素,我们初始化 Phaser 框架,它将所有内容渲染到 Canvas 元素中。

我们在标签中定义文档:字符集编码、页面标题和 CSS 样式。 通常我们会引用一个外部 CSS 文件,但在这里不是,正如我之前提到的,所有内容都将在 canvas 元素内呈现,因此我们不会有任何 HTML 元素。

最后要做的是包含所有 JS 文件:从包含 Phaser 框架所有源代码的 phaser.min.js 文件到包含所有游戏代码的文件。 为了减少浏览器请求次数,让游戏加载速度更快完美世界取消暂停代码,我们会在游戏需要的时候单独加载。

查看选项卡,我们在其中初始化框架并开始游戏。 自调用函数中第一行代码如下:

此代码将初始化 Phaser:

640 是游戏的画布宽度,960 是游戏的画布高度。

phaser.auto 通知框架我们希望如何将游戏渲染到画布上。 这里有三个选项:CANVAS、WEBGL和AUTO。 第一个在 2D Canvas 上渲染我们的游戏; 第二种尽可能使用WebGL来渲染游戏(现在主要用于桌面游戏,但移动支持会越来越好); 第三个通知框架,自动检查是否支持WebGL,从而决定游戏是如何渲染的,如果不支持WebGL,则使用2D Canvas。

完美世界取消暂停代码

帧初始化将分配给一个名为 game 的对象,该对象将在引用 Phaser 实例时使用。

以下代码行都是关于向我们的游戏添加状态的:

“Boot”是一个状态名称,Candy.Boot 是一个对象(在下面的代码中定义),当我们开始进入状态时将执行该对象。 我们为 Boot(配置)、Preloader(加载资产)、MainMenu(您猜对了,游戏的主菜单)和 Game(游戏的主循环)添加了状态。 最后一行,game.state.start("Boot"),启动 Boot 状态,Candy.Boot 对象将被执行。

如您所见,一个主要的 JavaScript 游戏对象已经创建。 在游戏中,我们有 Boot、Preloader、MainMenu 和 Game 对象,我们使用原型来定义它们。 这些对象中的一些特殊函数名是框架自己保留的(preload()、create()、update()和render()),但我们也可以定义自己的(startgame()、spawncandy()、managepause() ))。 如果您不确定自己是否理解所有这些内容,请不要担心,我将使用示例代码对所有内容进行解释。

游戏

让我们暂时忘记 Boot Preloader 和 MainMenu。 稍后将详细解释它们; 此时你需要知道的是,Boot状态决定了游戏的基本配置,Preloader会加载所有美术资源,MainMenu会显示开始游戏菜单。

让我们关注游戏本身并查看游戏代码。 在解释 game.js 代码之前,让我们从开发者的角度谈谈游戏概念本身。

人像模式

游戏是纵向模式。

在这种模式下,屏幕的高度大于它的宽度。 有的游戏适合竖屏(比如怪兽要糖),有的游戏适合横屏(包括平台游戏,比如Craigen),甚至有些类型的游戏两种模式都可以运行,通常这样的游戏比较难来写 。

游戏.js

在我们查看 game.js 文件之前,让我们先了解一下它的结构。 我们创造了一个游戏世界,里面有一个玩家角色,他的工作就是吃糖果。

游戏世界:怪物背后的世界是静止的。 背景是 Candy Land 的背景图像,前景是怪物,还有一个用户界面。

玩家角色:这个演示非常简单和基本,所以小怪物除了等待糖果外什么都不做。 玩家的主要任务是收集糖果。

糖果:游戏的核心机制是吃尽可能多的糖果。 糖果在屏幕的顶部边缘生成,玩家必须在它们掉落时点击(或点击)。 如果有糖果从屏幕底部掉落,将其拿走,玩家就会受到伤害。 我们还没有实现健康系统,所以一旦糖果从屏幕上掉下来,游戏就会立即结束并显示一条适当的消息。

好的,现在让我们看看 game.js:

Candy.Game 原型具有三个功能:

create() 初始化

managepause() 暂停和恢复游戏

update() 管理主游戏循环

我们将创建一个名为 item 的实用对象,它代表糖果。 它会有一些有用的方法:

spawncandy() 添加新的糖果

clickcandy() 当用户点击时,糖果消失

removecandy() 移除糖果

让我们看一下代码:

在这里,我们设置了所有将要使用的变量。

通过定义 this._name,我们将变量的范围限制在 Candy.Game 中。 这意味着它们不能在其他州使用——我们在其他地方不需要它们,那么为什么要暴露它们呢?

完美世界取消暂停代码

通过定义 Candy._name,我们允许这些变量在其他状态和对象中使用,例如,Candy._score 的值可以通过 Candy.item.clickCandy() 函数递增。

对象被初始化为空,计算所需的变量被初始化为零。

我们看一下candy.game.prototype的代码:

在create()函数的开头,我们设置了ARCADE物理系统——Phaser中有现成的,是最简单的。 之后,我们在游戏中加入了引力。 然后添加三张图片:背景、怪物、计分UI背景。 第四个添加的元素是暂停按钮。 请注意,我们使用了 candy.GAME_WIDTH 和 candy.GAME_HEIGHT 变量,它们在 Candy.Preloader() 中定义,但在整个游戏代码中都可用。

然后我们创建怪物,玩家的化身。 这是一个使用帧的动画精灵 - 一个精灵表。 为了让它看起来像站立时在呼吸,让我们为它制作动画。

animations.add() 函数创建帧动画,需要四个参数:

动画名称(以后可以参考)

包含所有框架的表格(我们只能使用其中的一些)

帧率

决定动画是否循环的标志

当要播放动画时,我们必须使用animations.play()来播放参数指定的动画。

我们将 spawncandytimer 设置为 0,将怪物生命值设置为 10。

文本样式

接下来的两行代码允许我们在屏幕上显示文本。 this.add.text() 函数有四个参数:屏幕左侧和顶部的绝对位置、实际文本字符串和配置对象。 我们可以像使用 CSS 一样格式化文本。 代码如下:

字体为Arial,40像素高,黄色,可以设置描边(颜色和粗细),文字居中对齐。

之后,我们定义糖果组和第一个糖果。

暂停游戏

挂起函数如下所示:

每次点击暂停按钮,我们将this.game.paused的状态更改为true,向玩家展示相应的提示,并创建一个事件监听器供玩家点击或点击屏幕。 当检测到点击或点击时,我们删除文本并将 this.game.paused 设置为 false。

paused 变量在游戏对象中是特殊的,因为它会暂停游戏中的所有动画和计算,所以一切都被冻结,直到我们取消暂停并将游戏暂停状态设置为 false。

更新周期

update() 函数名称是 Phaser 保留函数之一。 当你用这个名字命名一个函数时,它将在游戏的每一帧执行。

我们使用 spawncandytimer 变量来跟踪时间。 if 语句每秒检查一次,看它是否需要重置计时器,或者在游戏世界中生成一个新糖果(也就是说,每次它看到 spawncandytimer 相隔 1000 毫秒)。 然后,我们用forEach遍历糖果组中的所有糖果对象(屏幕上可以有多个糖果),给糖果的angle变量(糖果对象中存储的rotateMe)加上一个固定值,让它们落下定速旋转。 我们做的最后一件事是检查生命值是否已降至 0,如果是,则我们在屏幕上显示游戏结束并暂停游戏。

管理糖果活动

为了将糖果的逻辑与主Game分离,我们使用item来定义candy,其中包含函数:spawncandy()、clickcandy()和removecandy()。 为了方便,candy的部分变量保留在Game中,其他一些变量只存在于item的函数中,以达到更好的可维护性。

该函数首先定义了三个值:

完美世界取消暂停代码

随机掉落的糖果x坐标(取值在0到游戏画面宽度之间)

糖果的y坐标随机落下,根据糖果本身的高度

随机糖果类型(有五种不同的糖果图像)

然后我们添加一个糖果作为精灵,其起始位置和图像如上定义。 我们还需要为糖果生成过程设置动画帧。

接下来我们使用物理引擎让糖果从屏幕上方自然落下。 然后,我们启用糖果的点击输入并添加一个事件监听器。

为了确保糖果在离开游戏屏幕时被销毁,我们将 checkWorldBounds 设置为 true。 events.onOutOfBounds()函数会在糖果离开屏幕时被调用; 我们用它来调用 removecandy() 函数。 在糖果上设置锚点以使其绕轴旋转。 这里我们设置了 rotateMe 变量来在 update() 循环中旋转糖果; 我们选择一个介于 -2 和 +2 之间的值。 最后一行代码将新创建的糖果添加到糖果组中,这样我们就可以无休止地迭代它们。

我们来看下一个函数clickcandy():

这里需要用一个糖果作为参数,使用Phaser自带的方法kill()删除它。 我们还添加了 1 分,并更新了分数的文本。

重置糖果同样简短:

当糖果被点击或掉出屏幕时。 removecandy() 函数将被调用。 糖果对象被删除,玩家失去 10 条生命。 (游戏开始时玩家有10条生命,所以一颗糖果从屏幕上掉落,游戏结束)

原型和游戏状态

我们已经了解了游戏机制、核心概念和游戏玩法。 现在是时候查看其余代码了:缩放屏幕、加载资源、管理按钮点击等。

我们已经知道了游戏状态,让我们一一来看:

启动.js

boot.js 是我们将在其中定义主要游戏对象 Candy(您可以随意命名)的 JavaScript 文件。 这是 boot.js 文件的源代码:

如您所见,我们从 var Candy = {} 开始,为游戏创建一个全局对象。 所有对象都存储在其中,因此我们不会膨胀全局命名空间。

Candy.Boot = function(game){} 代码创建了一个名为 boot() 的新函数(由 index.html 调用),它将游戏对象作为参数(也由 index.html 中的框架创建)。

Candy.Boot.prototype = {} 代码是一种使用原型定义 Candy.Boot 内容的方式。

正如我之前提到的,Phaser 有一些保留的函数名称; preload() 和 create() 是其中的两个。 preload() 用于加载所有资源; create() 仅调用一次(在 preload() 之后),因此您可以将代码安排为对象,如定义变量或添加精灵。

我们的 Boot 对象包含这两个函数,因此它们可以被 Candy.Boot.preload() 和 Candy.Boot.create() 调用。 正如您在 boot.js 文件的完整源代码中所见,preload() 函数将图像加载到框架中:

this.load.image() 中的第一个参数是我们给图片起的名字,第二个是图片文件的路径。

为什么我们在boot.js文件中加载图片,用preload.js不行吗? 好吧,既然我们需要一个加载栏来显示所有资源(preload.js)的加载状态,那么就需要先加载它。

缩放选项

create() 函数包括一些特定于 Phaser 的输入和缩放设置:

第一行,input.maxpointers 设置为 1,我们的游戏不需要多点触控。

完美世界取消暂停代码

scale.scalemode 控制游戏的缩放比例。 可用设置有:EXACT_FIT、NO_SCALE 和 SHOW_ALL。 EXACT_FIT 会将游戏缩放到所有可用空间(100% 宽度和高度,非比例缩放); NO_SCALE 将禁用缩放; SHOW_ALL 将确保游戏适合给定的尺寸,并且所有内容都适合屏幕(按比例缩放)。

将 scale.pagealignhorizo​​ntally 和 scale.pagealignvertically 设置为 true 将使游戏水平和垂直居中。

调用 scale.setScreenSize(true) 以“激活”缩放。

最后一行 state.start('Preloader') 执行下一个状态,Preloader 状态。

预加载器.js

预加载功能加载了大量图片。 与preload()函数相比,create()函数非常简单完美世界取消暂停代码,因为create()函数只需要负责切换状态即可。

这是 preloader.js 源代码:

}; 类似于 boot.js; 定义 Preloader 对象,然后添加两个原型函数(preload() 和 create())。 在Prototype对象中,我们定义了两个变量:Candy.GAME_WIDTH和Candy.GAME_HEIGHTt; 他们设置了游戏画面的默认宽度和高度。

preload()前3行代码设置舞台背景色(#b4d9e7,淡蓝色)以显示游戏中的精灵,setPreloadSprite()函数将负责显示资源的加载进度。 让我们看看 add.sprite() 函数:

如您所见,我们需要三个值:绝对图像 x 坐标(舞台宽度减去图像宽度并除以 2)、图像绝对 y 坐标(类似计算)和图像名称(我们已经在 boot.js 文件中)。

加载精灵表

接下来的几行使用 load.image() (您已经看到)加载所有图形资源。

最后 3 行代码有点不同:

load.spritesheet() 函数不加载单个图像,而是加载 spritesheet。 两个额外的参数告诉函数单个图像的尺寸。

在 candy.png 中,我们有 5 种不同类型的糖果。 图片大小为410x98px,但是单个元素的大小为82x98px,定义在load.spritesheet()函数中。 播放器 spritesheet 以相同的方式加载。

create()函数启动游戏的下一个状态,MainMenu,当所有资源加载完成后会显示游戏菜单。

主菜单.js

这是渲染图像、添加按钮和添加游戏循环的地方。

MainMenu 没有 preload() 函数,因为资源已经加载到 Preload.js 中。

这里有2个函数,create(), startGame()。 先看startGame()函数:

该函数只负责启动游戏循环,不会自动执行,需要我们通过按钮触发。

create() 有 3 个 add.sprite() 函数,可将图像加载到舞台上。 我们的主菜单在背景上,角落里有小怪物,还有游戏的标题。

按钮

我们已经在游戏状态中使用了另一个对象,即按钮:

这个按钮看起来比我们之前的代码更复杂。 我们使用八个不同的参数创建按钮:x 位置、y 位置、图像(或精灵)的名称、单击按钮时要执行的函数、函数执行的上下文以及要使用的图像对于按钮。

推荐阅读