创建节点
设置关卡信息
实现关卡界面
为预制添加脚本
完善Game.js逻辑
在上一节教程中我们讲解了打砖块的主要功能与逻辑实现,在这一篇教程中,笔者会在它的基础上增加关卡功能(建议先阅读上一节教程)。
运行效果如下:
Cocos Creator版本:2.2.0
后台回复"关卡",获取该项目完整文件:
1. bg就是一个背景图片。
2. levelsLayout为一个布局节点,节点上的Layout组件属性设置如下(除了Type和Resize Mode,其他属性大家可以根据需要自行修改):
该节点用来对各个关卡进行布局,完成后样子如下:
3. level是一个预制节点,其子节点num用于提示当前关卡数,star节点用于提示是否已经通关(没有通关的时候为灰色,通关后变为黄色)。另外num节点初始状态不可见,只有玩家通过当前关卡后,后面一个关卡的数字才会显示(当然第一关在一开始就要显示数字)。
我们在scripts文件夹中新建一个Settings.js脚本,编写如下代码:
// Settings.js
let settings = [
{
level: 1, // 第1关
row: 3, // 行数
col: 3, // 列数
spaceX: 20, // 列间隔
spaceY: 20, // 行间隔
brickWidth: 200, // 砖块宽度
brickHeight: 100, // 砖块高度
levelState: 'UNLOCKED', // 关卡状态
transparentBricks: [[1,0], [2,2]] // 刚开始就透明的砖块
},
{
level: 2, // 第2关
row: 6,
col: 6,
spaceX: 10,
spaceY: 10,
brickWidth: 120,
brickHeight: 70,
levelState: 'LOCKED',
transparentBricks: [[3,5], [4,1], [3,4]]
},
{
level: 3, // 第3关
row: 9,
col: 9,
spaceX: 10,
spaceY: 10,
brickWidth: 100,
brickHeight: 50,
levelState: 'LOCKED',
transparentBricks: [[7,5], [3,1], [5,7],[7,2],[6,8],[7,7]]
},
{
level: 4, // 第4关
row: 12,
col: 15,
spaceX: 5,
spaceY: 5,
brickWidth: 80,
brickHeight: 40,
levelState: 'LOCKED',
transparentBricks: [[1,1], [2,2], [3,3],[4,4],[5,5],[6,6],[7,7],[8,8],[9,9]]
},
{
level: 5, // 第5关
row: 12,
col: 15,
spaceX: 5,
spaceY: 5,
brickWidth: 80,
brickHeight: 40,
levelState: 'LOCKED',
transparentBricks: [[1,1], [2,2], [3,3],[4,4],[5,5],[6,6],[7,7],[8,8],[9,9]]
},
{
level: 6, // 第6关
row: 13,
col: 13,
spaceX: 4,
spaceY: 4,
brickWidth: 60,
brickHeight: 30,
levelState: 'LOCKED',
transparentBricks: [[9,9], [1,1], [3,4],[5,4],[5,6],[7,6],[7,8],[8,10],[9,1]]
},
]
export {settings};
在这个脚本中我们就新建了一个JSON变量settings,其中每个数组元素都包含了相应关卡的具体配置(这里共有六个关卡)。这里笔者讲一下levelState和transparentBricks这两个键:
最后用export输出该变量,我们会在其他脚本中调用。
新建Select.js脚本,编写如下代码:
// Select.js
import {settings} from './Settings.js';
cc.Class({
extends: cc.Component,
properties: {
levelPrefab: cc.Prefab,
levelsLayout: cc.Node
},
// LIFE-CYCLE CALLBACKS:
onLoad () {
this.initLevels();
},
initLevels () {
if (!cc.sys.localStorage.getItem('settings')) {
for (let i=0; i
下面是对该脚本代码的解释:
在initLevels方法中,我们首先判断本地存储中是否有settings项。
如果没有的话,那么说明玩家第一次玩,于是我们就新建预制,并将Settings.js中的各个关卡信息保存到相应预制中,调用changePic方法来设置预制相应的图片(该方法会根据levelState来设置相应的图片)。最后我们要将所有关卡信息存入本地,我们之后也会在Game.js的win方法中更新关卡信息,而游戏以后也都会只从本地存储中读取关卡信息了(当然可以选择把本地存储改为服务器存储)。
如果有的话,那么说明玩家不是第一次玩了,于是我们就从本地中读取关卡信息,创建并设置预制。
新建Level.js脚本,添加代码如下:
// Level.js
cc.Class({
extends: cc.Component,
properties: {
unlockedPic: cc.SpriteFrame,
lockedPic: cc.SpriteFrame,
greyStarPic: cc.SpriteFrame,
yellowStarPic: cc.SpriteFrame,
},
// LIFE-CYCLE CALLBACKS:
onLoad () {
// 触摸监听
this.node.on('touchstart', this.onTouchStart, this);
},
changePic (levelState, num) {
// 更改图片
if (levelState == 'UNLOCKED') {
// 解锁关卡
this.node.children[0].active = true;
this.node.children[0].getComponent(cc.Label).string = num;
this.node.getComponent(cc.Sprite).spriteFrame = this.unlockedPic;
this.node.children[1].getComponent(cc.Sprite).spriteFrame = this.greyStarPic;
}
else if (levelState == 'PASSED') {
// 通关
this.node.children[0].active = true;
this.node.children[0].getComponent(cc.Label).string = num;
this.node.getComponent(cc.Sprite).spriteFrame = this.unlockedPic;
this.node.children[1].getComponent(cc.Sprite).spriteFrame = this.yellowStarPic;
}
else if (levelState == 'LOCKED') {
// 关卡未解锁
this.node.getComponent(cc.Sprite).spriteFrame = this.lockedPic;
this.node.children[1].getComponent(cc.Sprite).spriteFrame = this.greyStarPic;
}
},
onTouchStart () {
if (this.node.settings['levelState'] == 'LOCKED')
return;
// 将目标关卡信息存入本地,在Game.js中取出
cc.sys.localStorage.setItem('currentLevelInfo', JSON.stringify(this.node.settings));
cc.director.loadScene('打砖块');
}
});
下面是对该脚本代码的解释:
在Game.js脚本中,我们首先在onLoad方法中获取currentLevelInfo项,并设置相关变量:
// Game.js
onLoad () {
...
// 首先获取当前关卡信息
let currentLevelInfo = JSON.parse(cc.sys.localStorage.getItem('currentLevelInfo'));
this.level = currentLevelInfo['level']; // 第几关
this.row = currentLevelInfo['row']; // 行数
this.col = currentLevelInfo['col']; // 列数
this.spaceX = currentLevelInfo['spaceX']; // 列间隔
this.spaceY = currentLevelInfo['spaceY']; // 行间隔
this.brickWidth = currentLevelInfo['brickWidth']; // 砖块宽度
this.brickHeight = currentLevelInfo['brickHeight']; // 砖块高度
this.transparentBricks = currentLevelInfo['transparentBricks']; // 刚开始就透明的砖块
this.speed = 20; // bar移动速度
...
},
然后在initBricksLayout方法中根据当前关卡中的transparentBrick来设置透明砖块:
// Game.js
initBricksLayout () {
...
// 循环放置砖块
for (let i=0; i
最后我们在win方法中更新关卡信息,只用更改关卡中的levelState就行啦:
// Game.js
win () {
// 更新关卡信息
let settings = JSON.parse(cc.sys.localStorage.getItem('settings'));
settings[this.level-1]['levelState'] = 'PASSED'; // 当前关卡状态变为通过(数组下标-1)
settings[this.level]['levelState'] = 'UNLOCKED'; // 下一关卡状态变为解锁
cc.sys.localStorage.setItem('settings', JSON.stringify(settings));
console.log('恭喜过关!');
cc.director.loadScene('关卡');
},
好了,那么今天的教程就到这,希望大家有所收获~