https://segmentfault.com/a/1190000009212221

用这个例子来做修改,修改的功能点如下,也是原作者留白的内容

  • 游戏中字体的更换

  • 地面应该和小恐龙底部持平,而非屏幕底部,如何实现?

  • 现在三种苹果和炸弹的出现概率是随机的,如何调整它们各自的出现概率?

  • 现在苹果和炸弹出现的时间间隔是固定的,如何随着游戏进行加快节奏?

  • 如何调整游戏难度梯度?

  • 现在炸弹和苹果有可能会相邻出现,导致很难接到苹果而不碰到炸弹,如何避免?

游戏中字体的更换

1
2
3
4
title = game.add.text(game.world.centerX, game.world.height * 0.25, '0', {
font:'bold 60px Helvetica',
fill:'#f2bb15'
});

地面应该和小恐龙底部持平,而非屏幕底部,如何实现?

首先应该实现一个地板,

1
game.load.image('ground', '//peiwan.bs2dlssl.huanjuyun.com/da38bffbb5954779887ad623c5cc2b10.png');//预先加载地板的图片

像加man一样加到场景中:

1
2
3
4
5
6
//地面 
platforms =game.add.sprite(game.world.centerX, game.world.height * 0.84 , 'ground');
var groundImg = game.cache.getImage('ground');
platforms.width = game.world.width;
platforms.height = platforms.width/groundImg.width * groundImg.height;
platforms.anchor.setTo(0.5, 0);

注释掉苹果与游戏边缘碰撞的代码,因为现在要变成苹果与地板的碰撞。这里还是用物理碰撞overlap。

所以要碰撞的两个物体都要加入物理系统,才能开启物体的物理特性,苹果已经加入了,现在加入地板的:

1
game.physics.enable(platforms);

开启物理特性后的对象后就有了body属性,我们这里要用到body的allowGravity(是否启用重力效果);如果不用的话默认是true,它放在游戏里后就会自动下落直到出边界,很明显我们不是要这样的效果,地板是不用下沉的。

1
platforms.body.allowGravity = false;

最后跟man和apples一样检测碰撞并且执行碰撞后的函数就可以了

1
2
3
4
5
6
game.physics.arcade.overlap(platforms,apples,failgame,null ,this);
...
function failgame(platforms, apple){
apple.kill();
if (apple.type !== 'bomb') game.state.start('over', true, false, score);
}

在设置地板的过程中,开了debug,敲好用:

1
2
3
this.render=function(){
game.debug.body(platforms);
},

拓展一下,如果我的苹果掉落不需要消失,而是停留在地面上呢?

首先要知道,在Arcade物理引擎中,碰撞检测主要用到两个函数,一个是collide,还有一个是overlap。

collide方法与overlap的区别在于collide会影响两个要检测的对象之间的物理状态,比如使用collide函数去检测两个物体,如果物体碰撞了,那么这两个物体之间就会有力的相互作用,可能其中一个会被另一个弹开,或者两个之间相互弹开。

但如果使用overlap方法的话,则只会检测两个物体是否已经碰撞了,或者说已经重叠了,并不会产生物理作用。

所以如果是这样的情况,我们要使用collide来进行碰撞检测:

1
game.physics.arcade.collide(platforms, apples);

同时,地板需要在加一个属性:immovable,不设置的话,地板会被苹果砸下去

1
platforms.body.immovable = true;//设置是否固定不动

现在三种苹果和炸弹的出现概率是随机的,如何调整它们各自的出现概率?

首先看原来的代码:

1
2
3
4
5
6
7
8
9
10
11
12
// 添加苹果组
var apples = game.add.group();
// 苹果类型
var appleTypes = ['green', 'red', 'yellow'];
var appleTimer = game.time.create(true);
appleTimer.loop(1000, function() {
var x = Math.random() * game.world.width;
var y = Math.random() * game.world.height;
var type = appleTypes[Math.floor(Math.random() * appleTypes.length)];
apples.create(x, y, type);
});
appleTimer.start()

addloop两个方法,分别对应setTimeout和setInterval,效果是每隔1秒就会在屏幕随机位置出现一个苹果了,而且种类是随机的。

可以看出,掉落的种类主要是这一句:

var type = appleTypes[Math.floor(Math.random() * appleTypes.length)]

简单来说就是[0,1,2,3] 这个数组随机选一个随机数,现在我们要求的是给他们加权重,来选择随机数.

1
2
3
4
5
6
7
8
function weightedRand(spec) {
var i, sum=0, r=Math.random();
for (i in spec) {
sum += spec[i];
if (r <= sum) return i;
}
}
weightedRand({0:0.4, 1:0.2, 2:0.1,3:0.3});
1
var type = appleTypes[weightedRand({0:0.4, 1:0.2, 2:0.1,3:0.3})];

现在苹果和炸弹出现的时间间隔是固定的,如何随着游戏进行加快节奏?

原代码:

1
appleTimer.loop(1000, function () {})

所以我们首先要想获取游戏时间,然后让时间间隔随着游戏时间的增加来减少。

this.game.time.totalElapsedSeconds()可以计算从打开页面到现在的时间。demo

我想了下觉得,无限循环loop有些不适用,改成game.time.events.add(loopTime, appleDown,this);

苹果/炸弹的添加用个appleDown函数包起来,定义一个变量appleTimeInterval来记录游戏时间,根据游戏时间修改loopTime(间隔)。

1
2
3
4
5
6
7
8
9
10
11
12
function appleDown() {
...
/*以下为新增*/
appleTimeInterval= game.time.totalElapsedSeconds();
if(appleTimeInterval>10 && appleTimeInterval<20){
loopTime = 1000;
}else if(appleTimeInterval>20){
loopTime = 500;
}
console.log(loopTime)
game.time.events.add(loopTime, appleDown,this);
}

如何调整游戏难度梯度?

这比较笼统了,可以设定炸弹出现的频率或者缩短apple的时间间隔?

现在炸弹和苹果有可能会相邻出现,导致很难接到苹果而不碰到炸弹,如何避免?

这个问题看这段:

1
2
3
var x = Math.random() * game.world.width;
var type = appleTypes[weightedRand({0:0.4, 1:0.2, 2:0.1,3:0.3})];
var apple = apples.create(x, 0, type);

所以只要对比x的值,如果炸弹的x值跟上一个苹果的值太接近,我们就重新生成x的值:定义一个用来保存上一个x值的变量lastAppleX,当生成是炸弹时,才需要进行对比。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var appleWidth = game.world.width / 8;
var x = Math.random() * game.world.width;
var type = appleTypes[weightedRand({ 0: 0.4, 1: 0.2, 2: 0.1, 3: 0.3 })];

if (type == 'bomb') {
var twoDistance = Math.abs(lastAppleX - x);
console.log('间隔:' + twoDistance)
if (twoDistance < appleWidth) {
console.log('间隔太小')
appleDown();
return;
}
var apple = apples.create(x, 0, type);
lastAppleX = x; //记录上一个x
apple.type = type;

写到这里我又想起,如果是上一个是炸弹,然后是苹果呢?所以还要记录下type,并修改当本次与上次掉落不同东西才去对比:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (type !== lastType) {
console.log('different type')
var twoDistance = Math.abs(lastAppleX - x);
console.log('间隔:' + twoDistance)
if (twoDistance < appleWidth) {
console.log('间隔太小')
appleDown();
return;
}
}
var apple = apples.create(x, 0, type);
lastAppleX = x; //记录上一个x
apple.type = type;
lastType = apple.type;//记录上一个type

至此也就完成了原作者留白的功能点。但是如果要用到实际的项目中,我们还是可以再拓展。

运营活动中可能还需要这个游戏做些什么呢?

  1. 派券

    根据最后玩的分数,派出不同的券,假设50分以下为“30-5”优惠券,50-100分为“30-10”优惠券,100分以上是“20-10”优惠券。

    这里涉及几个必须的点:

    • 控制数量/成本,假设我有“30-5”的券20张,”30-10“的券10张,”20-10”的券5张;
    • 控制设备防刷,假定每个人每台设备一天只能玩一次;
  2. 分享

    这几乎是必然有的,微信分享本人的分数到朋友圈或者微信好友

1、2点涉及到游戏的over状态,取score值。根据score来操作即可。

控制设备的在游戏的preload开始场景,可以在这里进行判断,如果不符合则加载另外的提示,有时候也需要在over状态进行提示,可能用户不在乎领券只是想玩一下。

分享的可以有一个静态h5来替换游戏地址,上面显示用户分数。


修改后代码地址:
https://github.com/anchen1204/game/blob/master/pharser-apple-example1/demo/game.js

参考:

https://www.phaser-china.com/example.html

https://ryangun.github.io/2018/01/04/Phaser%E5%9F%BA%E7%A1%80%E7%AF%87%E4%B8%8A/