cocoscreator开发的出名游戏_用 CocosCreator 快速开发推箱子游戏

游戏总共分为4个功能模块:

- 开始游戏(menuLayer)

- 关卡选择(levelLayer)

- 游戏(gameLayer)

- 游戏结算(gameOverLayer)

Creator内组件效果如下:

eaa8c02a379df75ef27af9b685999e9e.png

游戏开始默认显示menuLayer,游戏中,通过控制各个层级的显示和隐藏,实现不同模块的切换。例如开始游戏,点击开始以后,触发回调函数,切换到游戏关卡选择界面,绑定关系如下图:

2f95b47c83d541e5cf4c2a4b52da9d50.png

实现代码如下:

// 开始按钮回调startBtnCallBack(event, customEventData){ if(this.curLayer == 1){ return; } this.curLayer = 1; this.playSound(sound.BUTTON);  this.menuLayer.runAction(cc.sequence( cc.fadeOut(0.1), cc.callFunc(() => { this.startBtn.stopAllActions(); this.startBtn.scale = 1.0; this.menuLayer.opacity = 255; this.menuLayer.active = false; } ))); this.levelLayer.active = true; this.levelLayer.opacity = 0; this.levelLayer.runAction(cc.sequence( cc.delayTime(0.1),  cc.fadeIn(0.1),  cc.callFunc(() => { this.updateLevelInfo(); } )));},

其他功能模块实现类似。以下将分4个模块分别讲述各个模块的实现。

1. 开始游戏 menuLayer

开始游戏模块,开始游戏后默认显示,其他模块隐藏,功能实现相对简单,界面布局完成以后,开始游戏按钮添加响应事件即可,实现代码如上,在此界面添加了一个小动画,让开始游戏按钮不断的放大缩小,代码如下:

// 主界面动画menuLayerAni(){ this.startBtn.scale = 1.0; this.startBtn.runAction(cc.repeatForever(cc.sequence( cc.scaleTo(0.6, 1.5),  cc.scaleTo(0.6, 1.0) )));},

实现后的效果:

c8880b44d90912ebd37342349333b443.gif

2. 关卡选择 levelLayer

关卡选择分两步:第一步,界面显示,通过配置文件,加载预制文件,显示所有关卡;第二步,根据游戏情况,更新每一关卡信息。

2.1 第一步显示关卡

游戏中所有关卡置于ScrollView控件上,每一个关卡,使用一个预制文件(levelItem),通过读取关卡配置文件,加载所有关卡,加载完成后重新计算ScrollView内容的高度,加载关卡代码如下:

// 创建关卡界面子元素createLavelItem (){ // 进入关卡level let callfunc = level => {  this.selectLevelCallBack(level); }; for(let i = 0; i < this.allLevelCount; i++){ let node = cc.instantiate(this.levelItemPrefab); node.parent = this.levelScroll; let levelItem = node.getComponent("levelItem"); levelItem.levelFunc(callfunc); this.tabLevel.push(levelItem); } // 设置容器高度 this.levelContent.height = Math.ceil(this.allLevelCount / 5) * 135 + 20;},

下图即是所有关卡预制的父节点:

17389ff5751f8fbbbf7de26e1a727595.png

预制脚本挂在到预制上:

163999a724d286b4e939b68d79d3fc77.png

2.2 第二步更新关卡

每一个levelItem预制上挂一个levelItem脚本组件,levelItem脚本组件负责更新信息,主要控制是否可点击、通关星数、关卡等级、点击进入,levelItem脚本组件更新UI代码如下:

/** * @description: 显示星星数量 * @param {boolean} isOpen 是否开启 * @param {starCount} 星星数量 * @param {cc.SpriteAtlas} levelImgAtlas 纹理图 * @param {number} level 关卡 * @return:  */showStar(isOpen, starCount, levelImgAtlas, level){ this.itemBg.attr({"_level_" : level}); if(isOpen){ this.itemBg.getComponent(cc.Sprite).spriteFrame = levelImgAtlas.getSpriteFrame("pass_bg"); this.starImg.active = true; this.starImg.getComponent(cc.Sprite).spriteFrame = levelImgAtlas.getSpriteFrame("point" + starCount); this.levelTxt.opacity = 255; this.itemBg.getComponent(cc.Button).interactable = true; } else{ this.itemBg.getComponent(cc.Sprite).spriteFrame = levelImgAtlas.getSpriteFrame("lock"); this.starImg.active = false; this.levelTxt.opacity = 125; this.itemBg.getComponent(cc.Button).interactable = false; } this.levelTxt.getComponent(cc.Label).string = level;},

玩家的通过的信息,通过配置存储文件,保存玩家通关信息,分为已通关、刚开启和未开启三种状态,具体实现如下:

// 刷新关卡上的信息updateLevelInfo(){ let finishLevel = parseInt(cc.sys.localStorage.getItem("finishLevel") || 0); //已完成关卡 for(let i = 1; i <= this.allLevelCount; i++){ // 完成的关卡 if(i <= finishLevel){ let data = parseInt(cc.sys.localStorage.getItem("levelStar" + i) || 0); this.tabLevel[i - 1].showStar(true, data, this.levelImgAtlas, i); } // 新开的关卡 else if(i == (finishLevel + 1)){ this.tabLevel[i - 1].showStar(true, 0, this.levelImgAtlas, i); } // 未开启关卡图 else{  this.tabLevel[i - 1].showStar(false, 0, this.levelImgAtlas, i); } }},

最终的显示效果如下图:

3a0cb5aff0cea61317ab7ad9b3720dee.png

3. 游戏 gameLayer

游戏也分为两步:第一步,显示界面;第二步,游戏操作判断

3.1 显示界面

游戏内使用levelConfig.json配置每一关卡信息,每个关卡游戏部分由多行多列的方格组成,每一个关卡信息包含content、allRow、allCol、heroRow、heroCol、allBox属性,allRow和allCol记录总共行数和列数,heroRow、heroCol记录英雄所在位置,allBox记录箱子的总数,content是核心,记录每个方格的属性,根据不同的属性显示不同的物体,如墙面、地面、物体、箱子,可以通过修改配置,增加任意关卡。

读取关卡所有数据,并根据每一个位置的属性,显示不同的实物。

根据配置创建关卡信息:

// 创建关卡createLevelLayer(level){ this.gameControlLayer.removeAllChildren(); this.setLevel(); this.setCurNum(); this.setBestNum(); let levelContent = this.allLevelConfig[level].content; this.allRow = this.allLevelConfig[level].allRow; this.allCol = this.allLevelConfig[level].allCol; this.heroRow = this.allLevelConfig[level].heroRow; this.heroCol = this.allLevelConfig[level].heroCol; // 计算方块大小 this.boxW = this.allWidth / this.allCol; this.boxH = this.boxW; // 计算起始坐标 let sPosX = -(this.allWidth / 2) + (this.boxW / 2); let sPosY = (this.allWidth / 2) - (this.boxW / 2); // 计算坐标的偏移量,运算规则(宽铺满,设置高的坐标) let offset = 0; if(this.allRow > this.allCol){ offset = ((this.allRow - this.allCol) * this.boxH) / 2; } else{ offset = ((this.allRow - this.allCol) * this.boxH) / 2; } this.landArrays = []; //地图容器 this.palace = []; //初始化地图数据 for(let i = 0; i < this.allRow; i++){ this.landArrays[i] = [];  this.palace[i] = []; } for(let i = 0; i < this.allRow; i++){ //每行 for(let j = 0; j < this.allCol; j++){ //每列 let x = sPosX + (this.boxW * j); let y = sPosY - (this.boxH * i) + offset; let node = this.createBoxItem(i, j, levelContent[i * this.allCol + j], cc.v2(x, y)); this.landArrays[i][j] = node; node.width = this.boxW; node.height = this.boxH; } } // 显示人物 this.setLandFrame(this.heroRow, this.heroCol, boxType.HERO);},

根据类型创建元素:

// 创建元素

createBoxItem(row, col, type, pos){

let node = new cc.Node();

let sprite = node.addComponent(cc.Sprite);

let button = node.addComponent(cc.Button);

sprite.spriteFrame = this.itemImgAtlas.getSpriteFrame("p" + type);

node.parent = this.gameControlLayer;

node.position = pos;

if(type == boxType.WALL){ //墙面,//墙面,命名为wall_row_col

node.name = "wall_" + row + "_" + col;

node.attr({"_type_" : type});

}

else if(type == boxType.NONE){ //空白区域,//墙面,命名为none_row_col

node.name = "none_" + row + "_" + col;

node.attr({"_type_" : type});

}

else{ //游戏界面,命名为land_row_col

node.name = "land_" + row + "_" + col;

node.attr({"_type_" : type});

node.attr({"_row_" : row});

node.attr({"_col_" : col});

button.interactable = true;

button.target = node;

button.node.on('click', this.clickCallBack, this);

if(type == boxType.ENDBOX){ //在目标点上的箱子,直接将完成的箱子数加1

this.finishBoxCount += 1;

}

}

this.palace[row][col] = type;

return node;

},

游戏的所有元素,放置在下图中gameControlLayer的上:

e73c8b1db391a3c38e2ae96cb24e0558.png

游戏开始后,显示的效果如下(第一关,其他关类似)

41f77f3627c6e7029aff878f4030ced8.png

3.2 游戏操作判断

路线计算好后,玩家移动,若玩家点击的是箱子区域,先检测箱子前方是否有障碍物,若没有则推动箱子,通过切换地图的图片和修改位置类型达到推动箱子的效果。

点击地图位置,获取最优路径,人物跑到指定点,实现如下:

// 点击地图元素clickCallBack : function(event, customEventData){ let target = event.target; //最小路径长度 this.minPath = this.allCol * this.allRow + 1; //最优路线 this.bestMap = []; //终点位置 this.end = {}; this.end.row = target._row_; this.end.col = target._col_; //起点位置 this.start = {}; this.start.row = this.heroRow; this.start.col = this.heroCol; //判断终点类型 let endType = this.palace[this.end.row][this.end.col]; if((endType == boxType.LAND) || (endType == boxType.BODY)){ //是空地或目标点,直接计算运动轨迹 this.getPath(this.start, 0, []); if(this.minPath <= this.allCol * this.allRow){ cc.log("从起点[
cocos creator实现的推箱子游戏,含源码和功能;游戏一共有100关卡。 cc.Class({ extends: cc.Component, properties: { // foo: { // // ATTRIBUTES: // default: null, // The default value will be used only when the component attaching // // to a node for the first time // type: cc.SpriteFrame, // optional, default is typeof default // serializable: true, // optional, default is true // }, // bar: { // get () { // return this._bar; // }, // set (value) { // this._bar = value; // } // }, starImg : cc.Node, itemBg : cc.Node, levelTxt : cc.Node, }, // LIFE-CYCLE CALLBACKS: onLoad () { }, start () { }, //--------显示星星数量-------- /** * @description: 显示星星数量 * @param {boolean} isOpen 是否开启 * @param {starCount} 星星数量 * @param {cc.SpriteAtlas} levelImgAtlas 纹理图 * @param {number} level 关卡 * @return: */ showStar : function(isOpen, starCount, levelImgAtlas, level){ this.itemBg.attr({"_level_" : level}); if(isOpen){ this.itemBg.getComponent(cc.Sprite).spriteFrame = levelImgAtlas.getSpriteFrame("pass_bg"); this.starImg.active = true; this.starImg.getComponent(cc.Sprite).spriteFrame = levelImgAtlas.getSpriteFrame("point" + starCount); this.levelTxt.opacity = 255; this.itemBg.getComponent(cc.Button).interactable = true; }else{ this.itemBg.getComponent(cc.Sprite).spriteFrame = levelImgAtlas.getSpriteFrame("lock"); this.starImg.active = false; this.levelTxt.opacity = 125; this.itemBg.getComponent(cc.Button).interactable = false; } this.levelTxt.getComponent(cc.Label).string = level; }, /
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值