先來(lái)說(shuō)下要實(shí)現(xiàn)的功能
- 根據(jù)一定規(guī)則生成關(guān)卡
- 實(shí)現(xiàn)消除等邏輯
- 游戲結(jié)束檢測(cè)
- 本地緩存游戲進(jìn)度
準(zhǔn)備工作
建好工程,使用編輯器搭建游戲場(chǎng)景。我搭建的場(chǎng)景如下圖:
簡(jiǎn)單說(shuō)明下:
- New Sprite是場(chǎng)景中的背景圖片
- StarRoot是一個(gè)空節(jié)點(diǎn),后面創(chuàng)建的星星方塊都會(huì)加到這個(gè)節(jié)點(diǎn)上
- ActionRoot是一些做動(dòng)作、動(dòng)畫(huà)節(jié)點(diǎn)的父節(jié)點(diǎn),像comb特效就在這個(gè)節(jié)點(diǎn)上
- UIRoot,就是用戶界面上的根節(jié)點(diǎn),像游戲的最高分、當(dāng)前分?jǐn)?shù)、當(dāng)前第幾關(guān)等等,都放在這個(gè)節(jié)點(diǎn)上
- ResultRoot是結(jié)算界面的根節(jié)點(diǎn)。顯示灰色是因?yàn)闆](méi)有激活這個(gè)節(jié)點(diǎn)
- SoundCTL也是一個(gè)空節(jié)點(diǎn),主要作用是在節(jié)點(diǎn)上掛載一個(gè)腳本處理游戲的聲音
制作星星預(yù)制
很簡(jiǎn)單,根節(jié)點(diǎn)下只有一個(gè)精靈節(jié)點(diǎn)。顯示藍(lán)色就表示是一個(gè)預(yù)制。主要說(shuō)一下star上的腳本組件starCtr.js
因?yàn)椴恢挂环N星星,所以需要改變New Sprite的紋理。星星有下面幾個(gè)屬性:
properties: {
_starType: 0,
_gx: 0,
_gy: 0,
starSprite: cc.Sprite,
starSpriteFrames: {
default: [],
type: cc.SpriteFrame,
},
},
starSprite對(duì)應(yīng)上圖New Sprite的Sprite組件;starSpriteFrames存儲(chǔ)了所有星星的紋理;_starType表示星星的類別,它決定了starSprite顯示starSpriteFrames中的哪個(gè)紋理;_gx、_gy用來(lái)存儲(chǔ)星星方塊在10x10地圖中的格子坐標(biāo)。
initStar (type, gx, gy) {
this._starType = type;
this.starSprite.spriteFrame = this.starSpriteFrames[this._starType];
this.updateGrid(gx, gy);
},
updateGrid (gx, gy) {
this._gx = gx;
this._gy = gy;
},
initStar星星的初始化函數(shù),updateGrid用來(lái)更新星星的坐標(biāo)位置
在預(yù)制里還做了一個(gè)操作,就是處理用戶的點(diǎn)擊操作,所以在腳本的start函數(shù)里監(jiān)聽(tīng)觸摸。start是組件腳本生命周期的回調(diào)函數(shù),會(huì)在組件第一次激活前,也就是第一次執(zhí)行update之前觸發(fā)。
start () {
this.node.on(cc.Node.EventType.TOUCH_START, function (event) {
//TODO:觸摸處理
}, this);
},
具體的觸摸處理后面說(shuō)。最后看下屬性檢查器里的腳本組件:
生成關(guān)卡數(shù)據(jù)
- 生成規(guī)則:每個(gè)格子隨機(jī)生成星星。(這里選取一個(gè)簡(jiǎn)單的邏輯規(guī)則,自己可以根據(jù)實(shí)際情況修改星星生成的邏輯)
- 用一個(gè)二維數(shù)組存儲(chǔ)10×10的地圖數(shù)據(jù)
下面介紹兩個(gè)對(duì)象,分別創(chuàng)建兩個(gè)腳本gamedata.js、Utils.js
gamedata處理游戲的數(shù)據(jù),像游戲的得分、當(dāng)前第幾關(guān)、地圖數(shù)據(jù)等等都存儲(chǔ)在里面。
// gamedata.js
var level = 0; //記錄當(dāng)前關(guān)卡
var targetScore = 0; //當(dāng)前關(guān)卡目標(biāo)分?jǐn)?shù)
var currScore = 0; //當(dāng)前得分
var bestScore = 0; //歷史最高得分
var starMatrix = null; //地圖數(shù)據(jù),二維數(shù)組
var starSprite = []; //一維數(shù)組,存儲(chǔ)星星的Node
module.exports = {
level: level,
targetScore: targetScore,
currScore: currScore,
bestScore: bestScore,
starMatrix: starMatrix,
starSprite: starSprite,
};
Utils主要是處理一些公用的邏輯,像關(guān)卡生成規(guī)則的邏輯就放這里了。
// Utils.js
var Config = require("psconfig");
var randomColorByArray = function (array) {
var i = Math.floor(Math.random() * array.length);
return array[I];
}
//隨機(jī)生成星星關(guān)卡邏輯
function initMatrixDataPortraitRandom () {
var matrixData = new Array(Config.matrixRow);
for(var row = 0; row < Config.matrixRow; row++) {
matrixData[row] = new Array(Config.matrixCol);
for(var col = 0; col < Config.matrixCol; col++) {
matrixData[row][col] = randomColorByArray(Config.totalColors);
}
}
return matrixData;
};
module.exports = {
initMatrixDataPortraitRandom: initMatrixDataPortraitRandom,
};
腳本Utils.js加載了另一個(gè)腳本psconfig.js,它主要存放游戲的一些配置,代碼如下:
//psconfig.js
var cellSize = 73; //星星紋理的邊長(zhǎng)
var matrixRow = 10; //地圖的行數(shù)(高)
var matrixCol = 10; //地圖的列數(shù)(寬)
var totalColors = [0,1,2,3,4]; //表示五種星星
module.exports = {
cellSize: cellSize,
matrixRow: matrixRow,
matrixCol: matrixCol,
totalColors: totalColors,
};
到這里,關(guān)卡數(shù)據(jù)已經(jīng)生成,下面就是根據(jù)生成的數(shù)據(jù)繪制星星地圖。
繪制星星
一開(kāi)始提到,創(chuàng)建的所有星星都會(huì)放在StarRoot的節(jié)點(diǎn)上。場(chǎng)景中StarRoot是一個(gè)空節(jié)點(diǎn),有一個(gè)腳本組件matrixCtr,看下圖:
單個(gè)格子邊長(zhǎng)73,格子間有2個(gè)像素的縫隙,所以StarRoot是邊長(zhǎng)748的正方形,把它的錨點(diǎn)設(shè)置在左下角,為了方便格子坐標(biāo)和像素位置坐標(biāo)之間的轉(zhuǎn)換。
在Utils腳本上添加兩個(gè)函數(shù)用于坐標(biāo)之間的轉(zhuǎn)換。
//Utils.js
function grid2Pos (gx, gy) {
var px = Config.cellSize * 0.5 + (Config.cellSize + 2) * gy;
var py = Config.cellSize * 0.5 + (Config.cellSize + 2) * gx;
return cc.v2(px, py);
};
function pos2Grid (px, py) {
var gx = (py - Config.cellSize * 0.5) / (Config.cellSize + 2);
var gy = (px - Config.cellSize * 0.5) / (Config.cellSize + 2);
return cc.v2(Math.round(gx), Math.round(gy));
};
最后別忘了導(dǎo)出,在module.exports中添加變量:
module.exports = {
grid2Pos: grid2Pos,
pos2Grid: pos2Grid,
initMatrixDataPortraitRandom: initMatrixDataPortraitRandom,
};
下面說(shuō)一下腳本matrixCtr.js
上圖中可以看到,腳本中有兩個(gè)預(yù)制類型的屬性star、particle,其中star就是開(kāi)始制作的星星預(yù)制。particle主要是播放粒子,是星星消除時(shí)的特效。
properties: {
starPrefab: cc.Prefab,
starParticle: cc.Prefab,
_starPool: null,
uiCtr: cc.Node,
actCtr: cc.Node,
combCtr: cc.Node,
soundCtr: cc.Node,
},
因?yàn)橛螒蛑幸l繁創(chuàng)建和銷毀星星,而這些操作是非常耗費(fèi)性能的,所以這里使用了對(duì)象池。關(guān)于它的介紹和使用方法參考官方文檔。
//matrixCtr.js
var Utils = require("Utils");
var Config = require("psconfig");
var GameData = require("gamedata");
onLoad () {
//初始化對(duì)象池
this._starPool = new cc.NodePool();
for(var i = 0; i < Config.matrixCol*Config.matrixRow; ++i) {
var star = cc.instantiate(this.starPrefab);
this._starPool.put(star);
}
}
onDestroy () {
this._starPool.clear();
},
createStar (type, gx, gy) {
var star = null;
if (this._starPool.size() > 0) {
star = this._starPool.get();
}
else {
star = cc.instantiate(this.starPrefab);
}
star.setPosition(Utils.grid2Pos(gx, gy));
this.node.addChild(star);
var starCtr = star.getComponent("starCtr");
starCtr.initStar(type, gx, gy);
return star
},
注意,這里省略了cc.Class等一些通用代碼,有了createStar函數(shù),我們就可以根據(jù)前面生成的數(shù)據(jù)來(lái)繪制星星了。
// matrixCtr.js
initMatrix () {
for(var row = 0; row < GameData.starMatrix.length; row++) {
var cols = GameData.starMatrix[row];
for(var col = 0; col < cols.length; col++) {
var type = cols[col];
var index = Utils.indexValue(row, col);
if (type >= 0) {
var node = this.createStar(type, row, col);
GameData.starSprite[index] = node;
}
else {
GameData.starSprite[index] = null;
}
}
}
},
initMatrix函數(shù)中使用了Utils腳本中的indexValue函數(shù)。這是因?yàn)榇鎯?chǔ)星星數(shù)據(jù)的是二維數(shù)組,存儲(chǔ)星星Node的是一維數(shù)組,它是兩者索引的轉(zhuǎn)換。當(dāng)然,存儲(chǔ)星星Node也可以使用二維數(shù)組。
//Utils.js
function indexValue (row, col) {
return row * Config.matrixCol + col;
};
function resolveIndex (index) {
var col = index % Config.matrixCol;
var row = (index - col) / Config.matrixCol;
return cc.v2(row, col);
};
別忘了在module.exports中導(dǎo)出變量,這里就省略了,最后上一張效果圖。