首先,我们需要一个在线编辑器。这里推荐使用菜鸟的前端工具:HTML/CSS/JS 在线工具 | 菜鸟工具
在打开的工具里,HTML一栏,输入下面的代码:
- html>
- <html>
- <head>
- <script src="https://cdn.jsdelivr.net/npm/phaser@3.15.1/dist/phaser-arcade-physics.min.js">script>
- head>
- <body>
-
- <script>
-
- script>
-
- body>
- html>
这段代码可以用作模板,引用了一个CDN上的phaser库。我们后来要写的代码需要添加到之间。
Phaser代码的基本结果如下:
- 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 ()
- {
- }
将上述代码放到模板中的之间后,在线工具的效果预览处,将出现游戏的黑屏效果,上面暂时没有其他东西,是因为我们什么都没有往里面加。
首先,我们把本课程要用到的图片上传到了这里,它们的路径如下:
1. 炸弹bomb: https://img-blog.csdnimg.cn/d21caf1056a14bc19e8476649a26539f.png
2. 星星star: https://img-blog.csdnimg.cn/61cad081ae31499e96a6e07327758328.png
3. 天空sky: https://img-blog.csdnimg.cn/019871af78a94614a90011defa9de90a.png
4. 地面/平台 ground: https://img-blog.csdnimg.cn/e21ef7cc9a4e4665892fed352efdbe33.png
5. 游戏角色 dude: https://img-blog.csdnimg.cn/421cc50b0bf04982b387e344c1a0c9d5.png
有了上面的图片后,我们可以在preload函数中,添加下面的代码了:
- function preload ()
- {
- this.load.image('sky', 'https://img-blog.csdnimg.cn/019871af78a94614a90011defa9de90a.png');
- this.load.image('ground', 'https://img-blog.csdnimg.cn/e21ef7cc9a4e4665892fed352efdbe33.png');
- this.load.image('star', 'https://img-blog.csdnimg.cn/61cad081ae31499e96a6e07327758328.png');
- this.load.image('bomb', 'https://img-blog.csdnimg.cn/d21caf1056a14bc19e8476649a26539f.png');
- this.load.spritesheet('dude',
- 'https://img-blog.csdnimg.cn/421cc50b0bf04982b387e344c1a0c9d5.png',
- { frameWidth: 32, frameHeight: 48 }
- );
- }
在create函数中添加下面的代码,就能出来基本的天空和星星图片了:
- function create ()
- {
- this.add.image(400, 300, 'sky');
- this.add.image(400, 300, 'star');
- }
我们给游戏中所有地面、平台编到一个组里,它们都是静止的东西,位置不相同而已。
如下面的代码,创建全局变量platforms,再替换一下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');
- }
为了能够正常运行,还需要修改一下前面已经添加过的游戏config变量。需要配置一下physics属性:
- 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
- }
- };
这时,便有了几个平台一样的东西出现在游戏里了。
继续在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
- });
-
- player.body.setGravityY(300);
-
- this.physics.add.collider(player, platforms);
其中player.setBounce(0.2);设置角色的弹跳系数,接近0时弹跳次数越少,设为1时永远不停地弹。player.setCollideWorldBounds(true);设置角色碰到世界的边界时是否检测碰到,是否将角色活动范围局限于可视的世界中。后面的三段代码分别创建一个动画:按下左键、转身、按下右键时的帧,分别为dude图片中的编号为0-3、4、5-8帧。
接下来的两行,player.body.setGravityY(300)可以为角色单独设置一个向下的重力,this.physics.add.collider(player, platforms);为物理世界添加了一个角色和平台之间的碰撞检测,有了这行代码,角色才能站立在平台和地面上,否则会往下面掉。
这时需要让角色动起来了!我们用下面的代码:
- cursors = this.input.keyboard.createCursorKeys();
-
- 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);
- }
有了这段代码,角色可以左右走动,也可以跳跃上平台了。如果跳不上去,可以酌情修改一下前面设置的角色的重力。
首先,生成一批星星从上方掉下来,为每一颗设置随机的弹跳系数,这样看起来会更有意思一些。
- 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);
-
- function collectStar (player, star)
- {
- star.disableBody(true, true);
- }
-
- this.physics.add.overlap(player, stars, collectStar, null, this);
一番操作后,移动角色,就可以摘到星星了。this.physics.add.collider(stars, platforms);指明了星星会掉落到平台上,而不会一直往下掉;this.physics.add.overlap(player, stars, collectStar, null, this); 可以让角色碰到星星时,执行一个叫collectStar的函数,这个函数里仅仅将触碰到的星星禁用隐藏了。
如果能够显示即时分数,那就更好了!那就干活吧!
首先,定义两个全局变量,一个定义分数,一个定义显示的文本。
- var score = 0;
- var scoreText;
在create函数里,添加上这么一行:
scoreText = this.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });
这表示在游戏中加上一个文本显示。
在collectStar函数中,添加分数增加的代码,最后如下:
- function collectStar (player, star)
- {
- star.disableBody(true, true);
-
- score += 10;
- scoreText.setText('Score: ' + score);
- }
这时应该能够显示分数了。
为了增强游戏的趣味性与挑战性,我们决定加上一个炸弹的元素。
继续在create函数代码上,增加这么几行:
- bombs = this.physics.add.group();
-
- this.physics.add.collider(bombs, platforms);
-
- function hitBomb (player, bomb)
- {
- this.physics.pause();
-
- player.setTint(0xff0000);
-
- player.anims.play('turn');
-
- gameOver = true;
- }
-
- this.physics.add.collider(player, bombs, hitBomb, null, this);
这段代码表示炸弹这个“组”加进来,也会与平台进行碰撞检测,弹跳。当角色碰到炸弹时,执行hitBomb函数,这时物理世界会暂停,角色变为红色,动画为正面像,gameOver变量为true。
刚才的代码只添加了bombs这个“组”,里面还没有炸弹呢。单个的炸弹什么时候出现呢?
我们决定在每一轮的星星接完之后出现一个新的炸弹。因此,把collectStar函数修改成下面这样,让每一次活跃的星星数为0时,重新将所有星星激活,移到屏幕上方再掉下来。与此同时,让炸弹“组”中随机产生一个炸弹,炸弹出现的位置为远离角色的一侧。
- 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);
-
- }
- }
到这里,游戏基本就能正常运行了!让我们一起来玩一玩吧!