先来说下要实现的功能
- 根据一定规则生成关卡
- 实现消除等逻辑
- 游戏结束检测
- 本地缓存游戏进度
准备工作
建好工程,使用编辑器搭建游戏场景。我搭建的场景如下图:
简单说明下:
- New Sprite是场景中的背景图片
- StarRoot是一个空节点,后面创建的星星方块都会加到这个节点上
- ActionRoot是一些做动作、动画节点的父节点,像comb特效就在这个节点上
- UIRoot,就是用户界面上的根节点,像游戏的最高分、当前分数、当前第几关等等,都放在这个节点上
- ResultRoot是结算界面的根节点。显示灰色是因为没有激活这个节点
- SoundCTL也是一个空节点,主要作用是在节点上挂载一个脚本处理游戏的声音
制作星星预制
很简单,根节点下只有一个精灵节点。显示蓝色就表示是一个预制。主要说一下star上的脚本组件starCtr.js
因为不止一种星星,所以需要改变New Sprite的纹理。星星有下面几个属性:
properties: {
_starType: 0,
_gx: 0,
_gy: 0,
starSprite: cc.Sprite,
starSpriteFrames: {
default: [],
type: cc.SpriteFrame,
},
},
starSprite对应上图New Sprite的Sprite组件;starSpriteFrames存储了所有星星的纹理;_starType表示星星的类别,它决定了starSprite显示starSpriteFrames中的哪个纹理;_gx、_gy用来存储星星方块在10x10地图中的格子坐标。
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星星的初始化函数,updateGrid用来更新星星的坐标位置
在预制里还做了一个操作,就是处理用户的点击操作,所以在脚本的start函数里监听触摸。start是组件脚本生命周期的回调函数,会在组件第一次激活前,也就是第一次执行update之前触发。
start () {
this.node.on(cc.Node.EventType.TOUCH_START, function (event) {
//TODO:触摸处理
}, this);
},
具体的触摸处理后面说。最后看下属性检查器里的脚本组件:
生成关卡数据
- 生成规则:每个格子随机生成星星。(这里选取一个简单的逻辑规则,自己可以根据实际情况修改星星生成的逻辑)
- 用一个二维数组存储10×10的地图数据
下面介绍两个对象,分别创建两个脚本gamedata.js、Utils.js
gamedata处理游戏的数据,像游戏的得分、当前第几关、地图数据等等都存储在里面。
// gamedata.js
var level = 0; //记录当前关卡
var targetScore = 0; //当前关卡目标分数
var currScore = 0; //当前得分
var bestScore = 0; //历史最高得分
var starMatrix = null; //地图数据,二维数组
var starSprite = []; //一维数组,存储星星的Node
module.exports = {
level: level,
targetScore: targetScore,
currScore: currScore,
bestScore: bestScore,
starMatrix: starMatrix,
starSprite: starSprite,
};
Utils主要是处理一些公用的逻辑,像关卡生成规则的逻辑就放这里了。
// Utils.js
var Config = require("psconfig");
var randomColorByArray = function (array) {
var i = Math.floor(Math.random() * array.length);
return array[i];
}
//随机生成星星关卡逻辑
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加载了另一个脚本psconfig.js,它主要存放游戏的一些配置,代码如下:
//psconfig.js
var cellSize = 73; //星星纹理的边长
var matrixRow = 10; //地图的行数(高)
var matrixCol = 10; //地图的列数(宽)
var totalColors = [0,1,2,3,4]; //表示五种星星
module.exports = {
cellSize: cellSize,
matrixRow: matrixRow,
matrixCol: matrixCol,
totalColors: totalColors,
};
到这里,关卡数据已经生成,下面就是根据生成的数据绘制星星地图。
绘制星星
一开始提到,创建的所有星星都会放在StarRoot的节点上。场景中StarRoot是一个空节点,有一个脚本组件matrixCtr,看下图:
单个格子边长73,格子间有2个像素的缝隙,所以StarRoot是边长748的正方形,把它的锚点设置在左下角,为了方便格子坐标和像素位置坐标之间的转换。
在Utils脚本上添加两个函数用于坐标之间的转换。
//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));
};
最后别忘了导出,在module.exports中添加变量:
module.exports = {
grid2Pos: grid2Pos,
pos2Grid: pos2Grid,
initMatrixDataPortraitRandom: initMatrixDataPortraitRandom,
};
下面说一下脚本matrixCtr.js
上图中可以看到,脚本中有两个预制类型的属性star、particle,其中star就是开始制作的星星预制。particle主要是播放粒子,是星星消除时的特效。
properties: {
starPrefab: cc.Prefab,
starParticle: cc.Prefab,
_starPool: null,
uiCtr: cc.Node,
actCtr: cc.Node,
combCtr: cc.Node,
soundCtr: cc.Node,
},
因为游戏中要频繁创建和销毁星星,而这些操作是非常耗费性能的,所以这里使用了对象池。关于它的介绍和使用方法参考官方文档。
//matrixCtr.js
var Utils = require("Utils");
var Config = require("psconfig");
var GameData = require("gamedata");
onLoad () {
//初始化对象池
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函数,我们就可以根据前面生成的数据来绘制星星了。
// 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函数中使用了Utils脚本中的indexValue函数。这是因为存储星星数据的是二维数组,存储星星Node的是一维数组,它是两者索引的转换。当然,存储星星Node也可以使用二维数组。
//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中导出变量,这里就省略了,最后上一张效果图。
写在最后
欢迎订阅,获取更多内容,掌握最新动态
如有疑问,欢迎添加微信讨论(验证:鸡毛信)
几个约定
- 不提供源码下载
- 文章会至少包含90%的源码,对60%的源码有说明
- 如转载文章,请务必注明
原文地址:https://www.cnblogs.com/monster0924/p/9858500.html