第四节 游戏暂停、分数记录、音频添加
这一节其实就是做一下收尾工作,完成以上三个功能后,一个标准的俄罗斯方块游戏就完成了。当然我们之后还会加上微信排行榜和好友分享等功能,不过在这一节我们只用看下标题中的这三个点。
游戏暂停
首先在层级管理器中添加一个按钮节点,命名为pauseResume,该按钮用暂停游戏(按一下暂停,再按一下继续):
利用Widget组件将按钮固定在屏幕右上角:
节点设置好后,我们来编写脚本。
首先在properties中加入如下属性:
// Game.js
properties: {
...
pauseResumeBtn: cc.Node,
pausePic: cc.SpriteFrame,
resumePic: cc.SpriteFrame,
},
- pauseResumeBtn就是按钮节点,当玩家点击按钮后我们要修改按钮的图片。
- pausePic是暂停图片。
- resumePic是播放(继续)图片。
接着在onLoad方法中添加一个变量,用于判断游戏当前是暂停还是继续:
// Game.js
onLoad () {
...
// 用于判断是否已经暂停
this.isPaused = false;
},
然后在左移、右移、旋转和下落四个按钮的事件函数开头加入判断——如果游戏已经暂停,则按钮点击无效:
// Game.js
leftBtn() {
if (this.isPaused)
return;
...
},
rotateBtn() {
if (this.isPaused)
return;
...
},
dropBtn() {
if (this.isPaused)
return;
...
},
rightBtn() {
if (this.isPaused)
return;
...
}
现在编写暂停按钮的事件函数pauseResume:
// Game.js
pauseResume() {
// 游戏暂停
if (!this.isPaused) {
this.isPaused = true; // 设置isPaused变量
this.unschedule(this.moveDown); // 取消计时器
let btnBg = this.pauseResumeBtn.children[0]; // 修改按钮背景
btnBg.getComponent(cc.Sprite).spriteFrame = this.resumePic;
}
else {
this.isPaused = false; // 设置isPaused变量
this.schedule(this.moveDown, 1); // 取消计时器
let btnBg = this.pauseResumeBtn.children[0]; // 修改按钮背景
btnBg.getComponent(cc.Sprite).spriteFrame = this.pausePic;
}
},
首先判断当前是否是暂停状态:
- 如果不是,则设置isPaused为true,取消掉计时器,并且重新设置按钮的图片,这样游戏就进入暂停状态了。
- 如果是,则设置isPaused为false,开启计时器,并且重新设置按钮的图片,这样游戏继续了。
最后在属性检查器中添加按钮的事件函数,然后将各相关节点拖入Game组件中就可以了(关于节点拖入以及按钮的事件函数设置的操作,笔者之后将不再赘述。请读者在编写好代码后记得将相关属性设置好,不然游戏运行会报错der~):
分数记录
同样我们现在层级管理器中添加一个Label控件,命名为score:
使用Widget组件将该节点固定在屏幕左上方:
因为分数会逐渐变大,位数会增加,那为了让文本在长度变化时不会超出屏幕,我们需要将锚点中的x坐标设置为0。这样左边就会固定住,文本只会向右边长:
接下来编写脚本。在properties中添加scoreLabel属性:
// Game.js
properties: {
...
scoreLabel: cc.Label, // 分数文本
},
在onLoad方法中添加一个this.score变量用来做加法运算:
// Game.js
onLoad () {
...
// 分数
this.score = 0;
},
然后我们编写一个addScore方法:
// Game.js
addScore() {
// 分数+1
this.score += 1;
this.scoreLabel.string = "分数:" + String(this.score);
},
非常简单,就是给this.score变量加上1,再调用String()转为字符串即可。
最后我们在dropConfirmedTiles调用addScore方法:
// Game.js
dropConfirmedTiles (lines) {
// 让其他未消除的方块下落
for (let i=0; i<lines.length; i++) {
for (let j=0; j<this.confirmedTileArray.length; j++) {
let confirmedY = Math.round(this.confirmedTileArray[j].y);
// 只有消除行上方的方块才允许下降
if (confirmedY <= -lines[i]*this.tileHeight)
continue;
this.confirmedTileArray[j].y -= this.tileHeight;
}
// 增加分数
this.addScore();
}
},
每消除一行,分数加上1。
运行截图如下:
音效添加
以下是笔者在这个游戏中将使用的音频文件:
- bg是背景音乐。
- btn是左右移动,旋转和重新开始按钮的音效。
- drop是下落音效。
- lose是失败音效
- pauseResume是暂停/继续音效。
- remove是消除音效。
在properties中添加如下属性:
// Game.js
properties: {
...
// 音频
bgAudio: {
default: null,
type: cc.AudioClip
},
btnAudio: {
default: null,
type: cc.AudioClip
},
dropAudio: {
default: null,
type: cc.AudioClip
},
pauseResumeAudio: {
default: null,
type: cc.AudioClip
},
removeAudio: {
default: null,
type: cc.AudioClip
},
loseAudio: {
default: null,
type: cc.AudioClip
}
},
首先我们在onLoad方法中循环播放背景音乐,为防止声音太大,可调用setMusicVolume方法设置音量:
// Game.js
onLoad () {
...
// 播放背景音乐
cc.audioEngine.playMusic(this.bgAudio, true);
cc.audioEngine.setMusicVolume(0.7);
},
然后分别给移动、旋转、下落、重新开始和暂停按钮添加音效(音效不循环播放):
// Game.js
leftBtn() {
if (this.isPaused)
return;
cc.audioEngine.playEffect(this.btnAudio, false);
...
},
rotateBtn() {
if (this.isPaused)
return;
cc.audioEngine.playEffect(this.btnAudio, false);
...
},
dropBtn() {
if (this.isPaused)
return;
cc.audioEngine.playEffect(this.dropAudio, false);
...
},
rightBtn() {
if (this.isPaused)
return;
cc.audioEngine.playEffect(this.btnAudio, false);
...
},
restart() {
// 重新开始
cc.audioEngine.playEffect(this.btnAudio, false);
cc.director.loadScene('俄罗斯方块');
},
pauseResume() {
...
cc.audioEngine.playEffect(this.pauseResumeAudio, false);
},
消除音效添加如下:
// Game.js
dropConfirmedTiles (lines) {
// 让其他未消除的方块下落
...
cc.audioEngine.playEffect(this.removeAudio, false);
},
最后是失败时候播放的音效:
// Game.js
lose () {
...
cc.audioEngine.stopMusic(); // 停止播放背景音乐
cc.audioEngine.playEffect(this.loseAudio); // 播放失败音效
},
游戏失败,则停止背景音乐,播放失败音效。
注:我们还可以直接调用stopMusic()来停止播放背景音乐,不需要传入音频ID,这个API更加方便。
到这里三个方面我们都已经实现了。有没有觉得记录分数的文本字体有点不好看?在下一节,笔者将教大家如何来制作自己的位图字体。