【phaser】快速实现HTML5 2d小游戏

简介: 使用 js 的 游戏框架 phaser 实现 html 小游戏

在我的博客阅读本文

前言

最近忙着看项目和写项目,在 github 上无意中发现了别人用 phaser 实现的2d小游戏,代码简单易懂,而且phaser框架本身就是非常的简单,非常适合想快速开发小游戏的开发者。但是国内关于 phaser3 的资料和教程甚少,于是笔者阅读官方学习文档简单实现了一个 2d 小游戏。因为官网本身有中文版的游戏实现教程,所以我在这里也就不做详细解读了,更多的是从学习笔记的角度来进行书写。

游戏源码和在线demo

在线demo

源码以及图片资源下载

如果你直接 push 下来源码在本地双击 html 文件是无法运行出来游戏的,该h5游戏需要在服务器环境中运行。因此笔者推荐使用vscode打开源文件,然后运行 firstgame.html 文件即可。

笔者这里建议可以优先把源码 clone 下来,tensteps文件夹是游戏开发中代码构建的过程,在看教程的过程中,可以参考。

在线demo也可以帮助理解。

准备工作

开发环境:vscode。并在vscode中安装 liveserver 插件,以创造服务器环境,满足h5游戏运行的条件。

phaser是否需要下载.? 我本人的建议是:直接在 html 文件中使用 cdn 即可。这里提供一下 phaser 的源码下载地址 ,供感兴趣的读者使用。

框架构建和解析

  • 新建文件夹 自定义名称
  • 将源文件中的素材文件 assets 文件夹复制到文件夹下。
  • 文件夹内新建 html 文件,这将是我们接下来编写代码的地方。

首先搭建整个游戏的框架。我们之后的代码将会在此框架下不断拓展。

<!doctype html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8" />
    <title>Making your first Phaser 3 Game - Part 1</title>
    <script src="//cdn.jsdelivr.net/npm/phaser@3.11.0/dist/phaser.js"></script>
    <style type="text/css">
        body {
            margin: 0;
        }
    </style>
</head>
<body>

<script type="text/javascript">

    var config = {
        type: Phaser.AUTO,
        width: 800,
        height: 600,
        scene: {
            preload: preload,
            create: create,
            update: update
        }
    };

    var game = new Phaser.Game(config);

    function preload ()
    {
    }

    function create ()
    {
    }

    function update ()
    {
    }

</script>

</body>
</html>

config 对象中包含了游戏的各种配置:画布显示的长宽,游戏的场景配置,type 指游戏的整体渲染。可以是Phaser.CANVAS,或者Phaser.WEBGL,或者Phaser.AUTO。我们在这里使用 AUTO ,它将自动尝试使用WebGL,如果浏览器或设备不支持,它将回退为Canvas。

scene 配置包含了 preload,create 和 update 。

  • preload 方法可自定义。使用它来加载各种自定义资源(图片,音乐等)。此方法由场景管理器在 init() 之后和 create() 之前调用,前提是场景具有 LoaderPlugin。
  • create 方法可自定义。使用它来创建您的游戏对象。通常在在 init() 和 preload() 之后被调用。
  • update 方法需要自行重写,当游戏运行时,该方法在每个游戏步骤中被调用。(英文原句为:This method is called once per game step while the scene is running. 翻译很一般 请自行体会。)因此我们可以考虑之后人物的走路判定方法编写在 update 方法中即实现游戏运行时其每一阶段都被调用一次。

资源加载

preload

框架搭建成功之后,我们将加载游戏所需要的资源。

    function preload ()
    {
        this.load.image('sky', 'assets/sky.png');
        this.load.image('ground', 'assets/platform.png');
        this.load.image('star', 'assets/star.png');
        this.load.image('bomb', 'assets/bomb.png');
        this.load.spritesheet('dude', 'assets/dude.png', { frameWidth: 32, frameHeight: 48 });
    }

这样将加载5个资源:4张图(image)和一个精灵表单(sprite sheet)。图片用于游戏中的各种场景显示,背景以及人物等等。

精灵表单则用于人物在走路时的动态显示。

create

要显示我们之前在 preload 中引入的各种资源的话,我们需要在 create 函数中使用 this.add.image() 方法。

我们先尝试加载一片蓝天与一颗星星。

在这里插入图片描述

function create ()
{
    this.add.image(400, 300, 'sky');
    this.add.image(400, 300, 'star');
}

只需要先加入add ’sky‘ 再add ’star‘ 即可。
400300是图像坐标的x值和y值。为什么是400和300呢?这是因为,在Phaser 3 中,所有游戏对象的定位都默认基于它们的中心点。这个背景图像的尺寸是800 x 600像素,所以,如果我们显示它时将它的中心定在0 x 0,你将只能看到它的右下角。如果我们显示它时定位在400 x 300,你能看到整体。

构建游戏世界

从现在开始我们将开始构建游戏内的各种场景,根据在线 demo 可知,我们需要几个平台以及背景图片。因此我们需要在create()函数中添加以下代码:

var platforms;

function create ()
{
    this.add.image(400, 300, 'sky');//生成游戏的图片背景天空
    
    platforms = this.physics.add.staticGroup();//添加物理组件组平台

    platforms.create(400, 568, 'ground').setScale(2).refreshBody();

    platforms.create(600, 400, 'ground');
    platforms.create(50, 250, 'ground');
    platforms.create(750, 220, 'ground');
}

我们在其中使用了this.physics 因此之前的游戏配置 config 也需要修改。修改后的config

var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 300 },
            debug: false
        }
    },
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};

新增了 physics 属性。

这些代码修改之后,我们的游戏场景就搭建成功了。效果如图下:

在这里插入图片描述

平台搭建代码详解

把目光再次锁定再我们刚刚修改过的create函数上,我们新增了一张天空的照片用作游戏的背景。

然后我们引入了platforms变量。

platforms = this.physics.add.staticGroup();

这一句生成一个静态物理组(Group),并把这个组赋值给局部变量platforms。在Arcade物理系统中,有动态的和静态的两类物体(body)。动态物体可以通过外力比如速度(velocity)、加速度(acceleration),得以四处移动。它可以跟其他对象发生反弹(bounce)、碰撞(collide),此类碰撞受物体质量和其他因素影响。

与此明显不同的是,静态物体只有位置和尺寸。重力对它没有影响,你不能给它设置速度,有东西跟它碰撞时,它一点都不动。名副其实,完全是静态的。因此将静态物体用作地面和平台很完美,我们打算让玩家在上面来回跑动。

那么什么是组呢?如其名所示,是把近似对象组织在一起的手段,控制对象全体就像控制一个统一的个体。你也可以检查组与其他游戏对象之间的碰撞。组能够生成自己的游戏对象,这是通过便利的辅助函数如create实现的。物理组会自动生成已经开启物理系统的子项(children),免得你使用多余的重复代码去新建更多的平台变量。

平台组做好了,我们现在可以用它生成平台:

platforms.create(400, 568, 'ground').setScale(2).refreshBody();

platforms.create(600, 400, 'ground');
platforms.create(50, 250, 'ground');
platforms.create(750, 220, 'ground');

上述代码的第一行,添加一张新的地面图像到400 x 568的位置(请记住,图像定位基于中心点)——问题是,我们需要这个平台撑满游戏的宽度。否则玩家就会掉出边界。

要做到这一点,我们用函数setScale(2)把它按x2(两倍)缩放。现在它的尺寸是800 x 64了,宽度正好和我们的游戏画布大小相同。要调用refreshBody(),这是因为我们缩放的是一个 静态 物体,所以必须把所作变动告诉物理世界(physics world)。

关于 refreshbody 方法。官方 docs 中的原话是这样的:Syncs the Body's position and size with its parent Game Object. You don't need to call this for Dynamic Bodies, as it happens automatically. But for Static bodies it's a useful way of modifying the position of a Static Body in the Physics World, based on its Game Object.

将Body的位置和大小与它的父游戏对象同步。你不需要为Dynamic Bodies调用这个,因为它会自动变化。但对于静态物体来说,这是基于其游戏对象在物理世界中修改静态物体位置的有效方法。

剩下的平台搭建代码:

platforms.create(600, 400, 'ground');
platforms.create(50, 250, 'ground');
platforms.create(750, 220, 'ground');

这个步骤跟前面完全相同,只是不需要缩放,因为他们的尺寸本来就正好。

接下来我们来添加玩家。

添加玩家

在我们的html文件中加入新的变量 player 并在 create() 函数中加入player 的一些设置即可。

create()player 相关的代码:

player = this.physics.add.sprite(100, 450, 'dude');

player.setBounce(0.2);
player.setCollideWorldBounds(true);

this.anims.create({
    key: 'left',
    frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
    frameRate: 10,
    repeat: -1
});

this.anims.create({
    key: 'turn',
    frames: [ { key: 'dude', frame: 4 } ],
    frameRate: 20
});

this.anims.create({
    key: 'right',
    frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }),
    frameRate: 10,
    repeat: -1
});

这段代码所做的事情就是生成一个精灵,然后生成精灵运动时的动画。

添加 sprite

player = this.physics.add.sprite(100, 450, 'dude');

player.setBounce(0.2);
player.setCollideWorldBounds(true);

这样生成一个新的精灵,叫player(玩家),位于100 x 450像素,在游戏的下部,该 sprite 的名称叫做 dude。精灵是通过物理游戏对象工厂函数(Physics Game Object Factory,即this.physics.add)生成的,这意味着它默认拥有一个动态物体。

sprite 和 image 的区别:

sprite 对象用于显示游戏中的静态和动画图像。精灵可以有输入事件和物理实体。它们还可以进行渐变、着色、滚动和动画。

sprite 和 image 的主要区别在于,你不能把 image 变成动画。因此,由于动画组件,精灵的处理时间更长,API占用也更大。如果你不需要动画,那么你可以在所有情况下使用 image 来替换 sprite 。

sprite 生成后,其被赋予0.2的一点点反弹(bounce)值。这意味着,它跳起后着地时始终会弹起那么一点点。然后精灵设置了与世界边界(bound)的碰撞。——边界默认在游戏尺寸之外。

setBounce(x [, y])

设置这个对象的反弹值。弹跳是物体与另一个物体碰撞时的复原量,或弹性。值为1表示它将在反弹后保持其全部速度。值为0意味着它不反弹。

我们(通过player.setCollideWorldBounds(true))把游戏(的世界边界)设置为800 x 600后,玩家就不能不跑出这个区域了。这样会让玩家停下来,不能跑出画面边界,或跳出顶边。

setCollideWorldBounds( [value] )

设置此物体是否与游戏世界边界碰撞。

如果需要该对象与游戏边界发生碰撞,则将 value 设为为 true,否则为false

动画实现

回顾一下preload函数,你会看到'dude'是作为精灵表单(sprite sheet)载入的,而非 image 。这是因为它包含了动画帧(frame)。完整的精灵表单是这个样子的:

在这里插入图片描述

总共有9帧,4帧向左跑动,1帧面向镜头,4帧向右跑动。

我们定义两个动画,叫'left'和'right'。这是'left'动画:

this.anims.create({
    key: 'left',
    frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
    frameRate: 10,
    repeat: -1
});

'left'动画使用0, 1, 2, 3帧,跑动时每秒10帧。'repeat -1'告诉动画要循环播放。

这是我们的标准跑动周期。反方向的动画把这些重复一下,键值用'right'。最后一个动画键值用'turn'(转身)。

 this.anims.create({
                key: 'turn',
                frames: [{ key: 'dude', frame: 4 }],
                frameRate: 20
            });

 this.anims.create({
                key: 'right',
                frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }),
                frameRate: 10,
                repeat: -1
            });
这里的 anims 对应的是 AnimationState 类. 这个组件提供了将动画应用到游戏对象的功能。

物理系统

Phaser支持多种物理系统,每一种都以插件形式运作,任何Phaser场景都能使用它们。针对本教程,我们将给我们的游戏使用Arcade物理系统,它简单,轻量,完美地支持移动浏览器。

物理精灵在生成时,即被赋予body(物体)属性,这个属性指向它的Arcade物理系统的Body。它表示精灵是Arcade物理引擎中的一个物体。物体对象有很多属性和方法,我们可以玩一下。

比如,在一个精灵上模仿重力效果,可以这么简单写:

player.body.setGravityY(300)

这是个随意的值,但逻辑讲,值越大你的对象感觉越重,下落越快。如果你把这些加到你的代码里,或者运行part5.html,你会看到玩家不停地往下落,完全无视我们先前生成的地面。

原因在于,我们还没有测试地面和玩家之间的碰撞。

当玩家和平台碰撞时,由于力的作用是相互的,玩家碰到它时,碰撞导致的力会作用于地面,因此两个物体交换彼此的速度,地面也开始下落。

要想玩家能与平台碰撞,且平台不动。我们可以生成一个碰撞对象。该对象监控两个物体(可以是组),检测二者之间的碰撞和重叠事件。如果发生事件,这时它可以随意调用我们的回调函数。不过仅仅就与平台间的碰撞而言,我们没必要那么做:

this.physics.add.collider(player, platforms);

碰撞器(Collider)接收两个对象,检测二者之间的碰撞,并使二者分开。在本例中,我们把玩家精灵和平台组传给它。最终实现玩家成功站在平台上的效果。
在这里插入图片描述

键盘控制

现在我们的游戏更像是一个动画,而非游戏,想要让它变的更像游戏一样,我们就应该向其中添加键盘控制,让玩家可以走动起来。

Phaser有内置的键盘管理器,用它的一个好处体现在这样一个方便的小函数:

cursors = this.input.keyboard.createCursorKeys();

这里把四个属性up, down, left, right(都是Key对象的实例),植入光标(cursor)对象。然后我们要做的就是在update循环中做这样一些if判断:

//在update函数中编写
if (cursors.left.isDown)
{
    player.setVelocityX(-160);

    player.anims.play('left', true);
}
else if (cursors.right.isDown)
{
    player.setVelocityX(160);

    player.anims.play('right', true);
}
else
{
    player.setVelocityX(0);

    player.anims.play('turn');
}

if (cursors.up.isDown && player.body.touching.down)
{
    player.setVelocityY(-330);
}

它做的第一件事,是查看方向左键是不是正被按下。如果是,我们应用一个负的水平速度,开动奔跑动画'left'。如果是方向右键正被按下,我们按字面意思做反向动作。通过清除速度值,再如此设置,一帧一帧,形成一个“走走停停”(stop-start)式的运动。

玩家只有键被按下时才移动,抬起时立即停止。键盘检测的最后部分,如果没有键被按下,就设置动画为'turn',水平速度为0。

代码的最后部分添加了跳起功能。方向up键是跳起键,我们检查它有没有被按下同时也检测玩家是不是正与地面接触,否则在半空中还会往上跳。(当然你也可以尝试实现二连跳的效果)

如果所有这些条件都符合,我们应用一个垂直速度,330像素每秒。玩家会由于重力的影响自动落回地面,控制已经就位,我们现在有了一个可以探索的游戏世界。请加载part7.html,或者运行自己的代码玩一玩。尝试调整各个值,比如跳起值330,调低,调高,看看会有什么效果。

收集星星

接下来我们添加星星让玩家收集,首先要做的就是让星星出现在游戏画面上。因为要批量生成星星,因此我们生成一个新的组,叫'stars',再充实它。在create函数中,我们加入如下代码(这些可以在part8.html中看到):

stars = this.physics.add.group({
    key: 'star',
    repeat: 11,
    setXY: { x: 12, y: 0, stepX: 70 }
});

stars.children.iterate(function (child) {

    child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));

});

这个过程跟我们生成平台组近似。但因为需要星星移动、反弹,我们生成动态物理组,而不是静态的。

组可以接收配置对象,以便于设置。在本例中,组配置对象有3个部分:

首先,它设置纹理key(键值)为星星图像。这意味着配置对象生成的所有子项,都将被默认地赋予星星纹理。然后,它设置重复值为11。因为它自动生成一个子项,重复11次就意味着我们总共将得到12颗,这正好是我们的游戏所需要的。

最后的部分是setXY——这用来设置组的12个子项的位置。每个子项都将如此放置:初始是x: 12,y: 0,然后x步进70。这意味着第一个子项将位于12 x 0;第二个离开70像素,位于82 x 0;第三个在152 x 0,依次类推。'step'(步进)值用于组生成子项时加以排布,真是很方便的手段。选用值70是因为,这意味着所有12个子项将完美地横跨着布满画面。

下一段代码遍历组中所有子项,给它们的bounce.y赋予0.4到0.8之间的随机值,反弹范围在0(不反弹)到1之间(完全反弹)。因为星星都是在y等于0的位置产出的,重力将把它们往下拉,直到与平台或地面碰撞为止。反弹值意味着它们将随机地反弹上来,直到最终恢复安定为止。

如果现在我们这样就运行代码,星星会落下并穿过游戏底边,消失不见了。要防止这个问题,我们就要检测它们与平台的碰撞。我们可以再使用一个碰撞器对象来做这件事:

this.physics.add.collider(stars, platforms);

与此类似,我们也将检测玩家是否与星星重叠:

this.physics.add.overlap(player, stars, collectStar, null, this);

这会告诉Phaser,要检查玩家与组中任何一颗星星的重叠。如果检测到,他们就会被传递到collectStar函数:

function collectStar (player, star)
{
    star.disableBody(true, true);
}

简单来说,星星带着个已关闭的物体,其父级游戏对象被设置为不活动、不可见,即将它从显示中移除。现在运行一下游戏,我们得到一个玩家,它左冲右突的,跳起,从平台反弹,收集头顶上落下的星星。不错,毕竟就这么几行、多半看起来还很好理解的代码.

在这里插入图片描述

计分

收集星星可以得分。接下来让我们来实现计分功能。

使用 text 对象即可。

在此我们生成两个新的变量,一个持有实际得分,一个文本对象本身:

var score = 0;
var scoreText;

scoreTextcreate函数中构建:

scoreText = this.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });

16 x 16是显示文本的坐标位置。score: 0 是要显示的默认字符串,接下来的对象包含字号、填充色。因为没有指定字体,实际上将用 Phaser 默认的,即 Courier 。

下一步我们要调整collectStar函数,以便玩家捡到一颗星星时分数会提高,文本会更新以反映出新状态:

function collectStar (player, star)
{
    star.disableBody(true, true);

    score += 10;
    scoreText.setText('Score: ' + score);
}

这样一来,每颗星星加10分,scoreText将更新,显示出新的总分。如果运行part9.html,你可以看到星星掉下来,收集星星时分数会提高。

在这里插入图片描述

弹球

现在该添加一些坏蛋,以此给我们的游戏收尾。

想法是这样的:你第一次收集到所有星星后,将放出一个炸弹。这个炸弹只是随机地在平台上各处跳,如果接触到它,你就死了。所有星星会重新产出,以便你可以再次收集,如果你完成了,又会放出另一个炸弹。这将给玩家一个挑战:别死掉,取得尽可能高的分数。

我们首先需要的东西是给炸弹用的一个组,还有几个碰撞器:

bombs = this.physics.add.group();

this.physics.add.collider(bombs, platforms);

this.physics.add.collider(player, bombs, hitBomb, null, this);

炸弹当然会跳出平台,如果玩家碰到它们,我们将调用hitBomb函数。这个函数所作的就是停止游戏,使玩家变成红色:

function hitBomb (player, bomb)
{
    this.physics.pause();

    player.setTint(0xff0000);

    player.anims.play('turn');

    gameOver = true;
}

现在看来还不错,不过我们要放出一个炸弹。要做到这一点,我们改一下collectStar函数:

function collectStar (player, star)
{
    star.disableBody(true, true);

    score += 10;
    scoreText.setText('Score: ' + score);

    if (stars.countActive(true) === 0)
    {
        stars.children.iterate(function (child) {

            child.enableBody(true, child.x, 0, true, true);

        });

        var x = (player.x < 400) ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);

        var bomb = bombs.create(x, 16, 'bomb');
        bomb.setBounce(1);
        bomb.setCollideWorldBounds(true);
        bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);

    }
}

我们使用一个组的方法countActive,看看有多少星星还活着。如果没有了,那么玩家把它们收集完了,于是我们使用迭代函数重新激活所有星星,重置它们的y位置为0。这将使所有星星再次从画面顶部落下。

下一部分代码生成一个炸弹。首先,我们取一个随机x坐标给它,始终在玩家的对侧画面,以便给玩家个机会。然后生成炸弹,设置它跟世界碰撞,反弹,拥有随机速度。

在这里插入图片描述

最终附上我们的所有源码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="//cdn.jsdelivr.net/npm/phaser@3.11.0/dist/phaser.js"></script>
    <style type="text/css">
        body {
            margin: 0;
        }
    </style>
</head>

<body>
    <script type="text/javascript">
        var config = {
            type: Phaser.AUTO,
            width: 800,
            height: 600,
            physics: {
                default: 'arcade',
                arcade: {
                    gravity: { y: 300 },
                    debug: false
                }
            },
            scene: {
                preload: preload,
                create: create,
                update: update
            }
        };
        var player;
        var stars;
        var platforms;
        var cursors;
        var score = 0;
        var scoreText;
        var bombs;
        var game = new Phaser.Game(config);

        function preload() {
            this.load.image('sky', 'assets/sky.png');
            this.load.image('ground', 'assets/platform.png');
            this.load.image('star', 'assets/star.png');
            this.load.image('bomb', 'assets/bomb.png');
            this.load.spritesheet('dude', 'assets/dude.png', { frameWidth: 32, frameHeight: 48 }
            );
        }

        function create() {
            this.add.image(400, 300, 'sky');

            platforms = this.physics.add.staticGroup();

            platforms.create(400, 568, 'ground').setScale(2).refreshBody();

            platforms.create(600, 400, 'ground');
            platforms.create(50, 250, 'ground');
            platforms.create(750, 220, 'ground');

            player = this.physics.add.sprite(100, 450, 'dude');
            this.physics.add.collider(player, platforms);

            player.setBounce(0.2);
            player.setCollideWorldBounds(true);

            this.anims.create({
                key: 'left',
                frames: this.anims.generateFrameNumbers('dude', { start: 0, end: 3 }),
                frameRate: 10,
                repeat: -1
            });

            this.anims.create({
                key: 'turn',
                frames: [{ key: 'dude', frame: 4 }],
                frameRate: 20
            });

            this.anims.create({
                key: 'right',
                frames: this.anims.generateFrameNumbers('dude', { start: 5, end: 8 }),
                frameRate: 10,
                repeat: -1
            });
            cursors = this.input.keyboard.createCursorKeys();

            stars = this.physics.add.group({
                key: 'star',
                repeat: 11,
                setXY: { x: 12, y: 0, stepX: 70 }
            });

            stars.children.iterate(function (child) {
                child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
            });
            this.physics.add.collider(stars, platforms);
            this.physics.add.overlap(player, stars, collectStar, null, this);

            scoreText = this.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });

            bombs = this.physics.add.group();
            this.physics.add.collider(bombs, platforms);
            this.physics.add.collider(player, bombs, hitBomb, null, this);

        }

        function update() {
            if (cursors.left.isDown) {
                player.setVelocityX(-160);
                player.anims.play('left', true);
            }
            else if (cursors.right.isDown) {
                player.setVelocityX(160);
                player.anims.play('right', true);
            }
            else {
                player.setVelocityX(0);

                player.anims.play('turn');
            }

            if (cursors.up.isDown && player.body.touching.down) {
                player.setVelocityY(-330);
            }
        }
        
        function collectStar(player, star) {
            star.disableBody(true, true);

            score += 10;
            scoreText.setText('score: ' + score);

            if(stars.countActive(true) === 0){
                stars.children.iterate(function(child){
                    child.enableBody(true, child.x, 0, true, true);
                });

                var x = (player.x < 400) ? Phaser.Math.Between(400, 800) : Phaser.Math.Between(0, 400);

                var bomb = bombs.create(x, 16, 'bomb');
                bomb.setBounce(1);
                bomb.setCollideWorldBounds(true);
                bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
            }
        }

        function hitBomb (player, bomb){
            this.physics.pause();
            player.setTint(0xff0000);
            player.anims.play('turn');
            gameOver = true;
            
        }
    </script>
</body>

</html>
目录
相关文章
|
3月前
|
JavaScript
用html,js和layui写一个简单的点击打怪小游戏
用html,js和layui写一个简单的点击打怪小游戏
25 0
|
3月前
|
移动开发 JavaScript 前端开发
用Html和js和layui写一个简单猜拳小游戏
用Html和js和layui写一个简单猜拳小游戏
40 0
|
3月前
|
算法 JavaScript Java
html+css+js实现打砖块小游戏
html+css+js实现打砖块小游戏
72 0
|
3月前
|
前端开发 算法 Java
html+css+js实现点球球小游戏
html+css+js实现点球球小游戏
22 0
|
5月前
|
移动开发 JavaScript 前端开发
HTML5兔子吃月饼手机小游戏
HTML5兔子吃月饼手机小游戏
34 0
|
12月前
|
移动开发 前端开发 Android开发
第22/90步《前端篇》第4章 编写一个简单的HTML5小游戏:移植及优化 第13课
今天学习《前端篇》第4章移植及优化的第13课,移植文本与图像。
100 0
|
12月前
|
移动开发 前端开发 JavaScript
第21/90步《前端篇》第4章 编写一个简单的HTML5小游戏:移植及优化 第12课
今天学习《前端篇》第4章移植及优化的第12课,移植音频和事件。
96 0
|
12月前
|
移动开发 前端开发 开发者
第20/90步《前端篇》第4章 编写一个简单的HTML5小游戏:移植及优化 第11课
今天学习《前端篇》第4章移植及优化的第11课,处理移植准备工作。
124 0
|
12月前
|
移动开发 前端开发 JavaScript
第19/90步《前端篇》第3章 编写一个简单的HTML5小游戏:完成交互功能 第10课
今天学习《前端篇》第3章完成交互功能的第10课,控制游戏音效,添加单击音效和背景音乐。
54 0
|
12月前
|
移动开发 前端开发 HTML5
第18/90步《前端篇》第3章 编写一个简单的HTML5小游戏:完成交互功能 第9课
今天学习《前端篇》第3章完成交互功能的第9课,实现游戏的重启功能。
46 0