cocos creator实例

阅读: 评论:0

cocos creator实例

cocos creator实例

用 CocosCreator 快速开发推箱子游戏

目录

用 CocosCreator 快速开发推箱子游戏

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

- 开始游戏(menuLayer)

- 关卡选择(levelLayer)

- 游戏(gameLayer)

- 游戏结算(gameOverLayer)


Creator内组件效果如下:

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

根节点Canvas挂载脚本gameLayer.js;绑定如下:


首先来处理开始游戏menuLayer的功能

- 开始游戏(menuLayer)

startBtn开始游戏按钮:设计成Node类型,有个缩放特效动画;下面添加Label和Button系统组件,用于添加文字显示个点击响应;如下:

开始按钮动画menuLayerAni

    //开始按钮动画menuLayerAni : function(){this.startBtn.scale = 1.0;this.startBtn.peatForever(cc.sequence(cc.scaleTo(0.6, 1.5), cc.scaleTo(0.6, 1.0))));},

startBtnCallBack开始按钮响应事件的处理

// 开始按钮回调startBtnCallBack(event, customEventData){if(this.curLayer == 1)return;//关卡UIthis.curLayer = 1;this.playSound(sound.BUTTON);//UI切换效果--menuLayer隐藏uLayer.runAction(cc.sequence(cc.fadeOut(0.1), cc.callFunc(function(){this.startBtn.stopAllAction();this.startBtn.scale = 1.uLayer.opacity = uLayer.active = false;}, this)));//UI切换效果--levelLayer激活this.levelLayer.active = true;this.levelLayer.opacity = 0;this.levelLayer.runAction(cc.sequence(cc.delayTime(0.1), cc.fadeIn(0.1), cc.callFunc(function(){this.updateLevelInfo();}, this)));},

播放音效 playSound

//播放音效playSound : function(name){cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {var audioID = cc.audioEngine.playEffect(clip, false);});},

开始游戏menuLayer的UI如下:

 


第二步是来实现关卡选择levelLayer的功能:

- 关卡选择(levelLayer)

关卡选择分两步:

第一步,界面显示,通过配置文件,加载预制文件,显示所有关卡;

第二步,根据游戏情况,更新每一关卡信息。

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

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

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

预制体、预制脚本的挂载:

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

    //--------显示星星数量--------   /*** @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){Component(cc.Sprite).spriteFrame = SpriteFrame("pass_bg");this.starImg.active = true;Component(cc.Sprite).spriteFrame = SpriteFrame("point" + starCount);this.levelTxt.opacity = 255;Component(cc.Button).interactable = true;}else{Component(cc.Sprite).spriteFrame = SpriteFrame("lock");this.starImg.active = false;this.levelTxt.opacity = 125;Component(cc.Button).interactable = false;}Component(cc.Label).string = level;},

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

    //2.刷新关卡上的信息updateLevelInfo : function(){//已完成关卡let finishLevel = parseInt(cc.Item("finishLevel") || 0);for(let i = 1; i < this.allLevelCount; i++){if(i <= finishLevel){   //完成的关卡显示星星个数let data = parseInt(cc.Item("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);}}},

最终的显示效果如下图:

 


第三步是来实现游戏界面gameLayer的功能:

- 游戏(gameLayer)

游戏也分为两步:

第一步,显示界面;

第二步,游戏操作判断

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


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

根据配置创建关卡信息:

//创建关卡createLevelLayer : function(level){veAllChildren();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 = ateBoxItem(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 : function(row, col, type, pos){let node = new cc.Node();let sprite = node.addComponent(cc.Sprite);let button = node.addComponent(cc.Button);sprite.spriteFrame = SpriteFrame("p" + type);node.parent = this.gameControlLayer;node.position = pos;if(type == boxType.WALL){  //墙面,//墙面,命名为wall_row_colnode.name = "wall_" + row + "_" + col;node.attr({"_type_" : type});}else if(type == boxType.NONE){  //空白区域,//墙面,命名为none_row_colnode.name = "none_" + row + "_" + col;node.attr({"_type_" : type});}else{  //游戏界面,命名为land_row_colnode.name = "land_" + row + "_" + col;node.attr({"_type_" : type});node.attr({"_row_" : row});node.attr({"_col_" : col});button.interactable = true;button.target = de.on('click', this.clickCallBack, this);if(type == boxType.ENDBOX){  //在目标点上的箱子,直接将完成的箱子数加1this.finishBoxCount += 1;}}this.palace[row][col] = type;return node;},

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

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

 

3.2 游戏操作判断

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

点击地图位置,获取最优路径,人物跑到指定点

clickCallBack : function(event, customEventData){let target = event.target;//最小路径长度this.minPath = this.allCol * this.allRow + 1;//最优路线this.bestMap = [];//终点位置d = {};w  = target._row_;l = target._col_;//起点位置this.start = {};w = this.heroRow;l = this.heroCol;//判断终点类型let endType = this.d.row][l];if((endType == boxType.LAND) || (endType == boxType.BODY)){  //是空地或目标点,直接计算运动轨迹Path(this.start, 0, []);if(this.minPath <= this.allCol * this.allRow){cc.log("从起点[", w, ",", l, "]到终点[", w, ",", l, "]最短路径长为:", this.minPath, "最短路径为:");cc.log("[", w, ",", l, "]");for(let i = 0; i< this.bestMap.length;i++){cc.log("=>[",this.bestMap[i].row,",",this.bestMap[i].col,"]");}this.bestMap.unshift(this.start);this.runHero();}else{console.log("找不到路径到达");}}else if((endType == boxType.BOX) || (endType == boxType.ENDBOX)){ //是箱子,判断是否可以推动箱子//计算箱子和人物的距离let lr = w - w;let lc = l - l;if((Math.abs(lr) + Math.abs(lc)) == 1){  //箱子在人物的上下左右方位//计算推动方位是否有障碍物let nextr = w + lr;let nextc = l + lc;let t = this.palace[nextr][nextc];if(t && (t != boxType.WALL) && (t != boxType.BOX) && (t != boxType.ENDBOX)){  //前方不是障碍物,也不是墙壁,推动箱子this.playSound(sound.PUSHBOX);//人物位置还原this.setLandFrame(w, l, this.palace[w][l]);//箱子位置类型let bt = this.d.row][l];if(bt == boxType.ENDBOX){      //有目标物体的箱子类型,还原成目标点this.d.row][l] = boxType.BODY;this.finishBoxCount -= 1;}else{this.d.row][l] = boxType.LAND;}//箱子位置变成人物图,但类型保存为空地或目标点this.d.row, l, boxType.HERO);//箱子前面位置变成箱子let nt = this.palace[nextr][nextc];if(nt == boxType.BODY){  //有目标点,将箱子类型设置成有目标箱子this.palace[nextr][nextc] = boxType.ENDBOX;this.finishBoxCount += 1;}else {this.palace[nextr][nextc] = boxType.BOX;}this.setLandFrame(nextr, nextc, this.palace[nextr][nextc]);this.curStepNum += 1;//刷新步数this.setCurNum();//刷新人物位置this.heroRow = w;this.heroCol = l;this.checkGameOver();}else{this.playSound(sound.WRONG);console.log("前方有障碍物");}}else{   //目标点错误this.playSound(sound.WRONG);console.log("目标点错误");}}},

 

获取最优路径算法:

//curPos记录当前坐标,step记录步数getPath : function(curPos, step, result){//判断是否到达终点if((w == w) && (l == l)){if(step < this.minPath){this.bestMap = [];for(let i = 0; i < result.length; i++){this.bestMap.push(result[i]);}this.minPath = step; //如果当前抵达步数比最小值小,则修改最小值result = [];}}//递归for(let i = (w - 1); i <= (w + 1); i++){for(let j = (l - 1); j <= (l + 1); j++){//越界跳过if((i < 0) || (i >= this.allRow) || (j < 0) || (j >= this.allCol)){continue;}if((i != w) && (j != l)){//忽略斜角continue;}else if(this.palace[i][j] && ((this.palace[i][j] == boxType.LAND) || (this.palace[i][j] == boxType.BODY))){let tmp = this.palace[i][j];this.palace[i][j] = boxType.WALL;  //标记为不可走//保存路线let r = {};r.row = l = j;result.push(r);Path(r, step + 1, result);this.palace[i][j] = tmp;  //尝试结束,取消标记result.pop();}}}},

 


第四步是来实现游戏结算界面gameOverLayer的功能:

- 游戏结算(gameOverLayer)

游戏结束后,根据成功推到箱子数,判断游戏是否成功,游戏成功以后,更新关卡信息即可。

判断逻辑如下:

//游戏结束检测checkGameOver : function(){let count = this.allLevelConfig[this.curLevel].allBox;if(this.finishBoxCount == count){   //全部推到了指定位置this.gameOverLayer.active = true;this.gameOverLayer.opacity = 1; this.gameOverLayer.runAction(cc.sequence(cc.delayTime(0.5), cc.fadeIn(0.1)));//刷新完成的关卡数let finishLevel = parseInt(cc.Item("finishLevel") || 0);  //已完成关卡if(this.curLevel > finishLevel){cc.sys.localStorage.setItem("finishLevel", this.curLevel);}//刷新星星等级cc.sys.localStorage.setItem("levelStar" + this.curLevel, 3);//刷新最优步数let best = parseInt(cc.Item("levelBest" + this.curLevel) || 0);if((this.curStepNum < best) || (best == 0)){cc.sys.localStorage.setItem("levelBest" + this.curLevel, this.curStepNum);}this.playSound(sound.GAMEWIN);this.clearGameData();}},

CC组件布局:

 

完整代码:

//--------levelItem.js--------
// Learn cc.Class:
//  - [Chinese] .html
//  - [English] .html
// Learn Attribute:
//  - [Chinese] .html
//  - [English] .html
// Learn life-cycle callbacks:
//  - [Chinese] .html
//  - [English] .htmlcc.Class({extends: cc.Component,properties: {starImg : cc.Node,itemBg : cc.Node,levelTxt : cc.Node,},onLoad : function (){},//显示星星数量showStar : function(isOpen, starCount, levelImgAtlas, level){this.itemBg.attr({"_level_" : level});if(isOpen){Component(cc.Sprite).spriteFrame = SpriteFrame("pass_bg");this.starImg.active = true;Component(cc.Sprite).spriteFrame = SpriteFrame("point" + starCount);this.levelTxt.opacity = 255;Component(cc.Button).interactable = true;}else{Component(cc.Sprite).spriteFrame = SpriteFrame("lock");this.starImg.active = false;this.levelTxt.opacity = 125;Component(cc.Button).interactable = false;}Component(cc.Label).string = level;},btnCallBack : function(event, customEventData){if(this._callfunc){this._callfunc(this.itemBg._level_);}},levelFunc : function(callfunc){this._callfunc = callfunc;}
});
//--------gameLayer.js--------
// Learn cc.Class:
//  - [Chinese] .html
//  - [English] .html
// Learn Attribute:
//  - [Chinese] .html
//  - [English] .html
// Learn life-cycle callbacks:
//  - [Chinese] .html
//  - [English] .html//方块类型
let boxType = {NONE : 0,   //无效位置WALL : 1,   //墙面LAND : 2,   //地面BODY : 3,   //物体BOX : 4,    //箱子ENDBOX : 5, //合体后的箱子HERO : 6    //人物
}//音效名称
let sound = {BUTTON : "Texture/sound/button",      //按钮点击音效GAMEWIN : "Texture/sound/gamewin",    //过关音效MOVE : "Texture/sound/move",          //人物移动音效PUSHBOX : "Texture/sound/pushbox",    //推箱子音效WRONG : "Texture/sound/wrong",        //错误音效
}cc.Class({extends: cc.Component,properties: {bg : cc.Node,menuLayer : cc.Node,    //主界面层levelLayer : cc.Node,   //关卡选择层gameLayer : cc.Node,    //游戏层gameControlLayer : cc.Node, //游戏操作层gameOverLayer : cc.Node,    //游戏结束层//主界面元素startBtn : cc.Node,titleImg : cc.Node,iconImg : cc.Node,loadingTxt : cc.Node,//关卡界面元素levelScroll : cc.Node,levelContent : cc.Node,//游戏界面元素levelTxt : cc.Node,curNum : cc.Node,bestNum : cc.Node,//合图itemImgAtlas: cc.SpriteAtlas,levelImgAtlas: cc.SpriteAtlas,levelItemPrefab : cc.Prefab,},onLoad : function(){//记录当前界面this.curLayer = 0;  //0-主界面,1-关卡界面,2-游戏界面//清理游戏中的数据this.clearGameData();//初始化游戏数据,加载游戏配置this.initData();//显示游戏主界面uLayer.active = true;this.levelLayer.active = false;this.gameLayer.active = false;this.gameOverLayer.active = false;this.loadingTxt.active = true;Component(cc.Button).interactable = false;//背景图适配this.fitNode(this.bg);uLayerAni();},// 适配结点fitNode: function (obj) {let canvasSize = CanvasSize();let canvasScale = canvasSize.width / canvasSize.height;let designScale = 720 / 1280;this.bg.height = 1280 * (designScale / canvasScale);},initData : function(){//初始化数据this.boxWidth = 90;this.boxHeight = 90;this.allWidth = 720;this.allHeight = 1280;this.allRow = 8;this.allCol = 8;this.allLevelCount = 0;this.allLevelConfig = {};cc.loader.loadRes('levelConfig.json', function (err, object) {if (err) {console.log(err);return;}this.allLevelConfig = object.json.level;this.allLevelCount = object.json.levelCount;this.loadingTxt.active = false;Component(cc.Button).interactable = true;//加载完配置后,直接创建关卡元素ateLavelItem();}.bind(this));this.tabLevel = [];},//创建关卡界面子元素createLavelItem : function(){let callfunc = function(level){//进入游戏界面this.selectLevelCallBack(level);}.bind(this);for(let i = 0; i < this.allLevelCount; i++){let node = cc.instantiate(this.levelItemPrefab);node.parent = this.levelScroll;let levelItem = Component("levelItem");levelItem.levelFunc(callfunc);this.tabLevel.push(levelItem);}//设置容器高度this.levelContent.height = il(this.allLevelCount / 5) * 135 + 20;},//刷新关卡上的信息updateLevelInfo : function(){let finishLevel = parseInt(cc.Item("finishLevel") || 0);  //已完成关卡for(let i = 1; i <= this.allLevelCount; i++){if(i <= finishLevel){  //完成的关卡显示星星个数let data = parseInt(cc.Item("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);}}},//主界面动画menuLayerAni : function(){this.startBtn.scale = 1.0;this.startBtn.peatForever(cc.sequence(cc.scaleTo(0.6, 1.5), cc.scaleTo(0.6, 1.0))));},//开始按钮回调startBtnCallBack : function(event, customEventData){if(this.curLayer == 1){return;}this.playSound(sound.BUTTON);this.curLayer = uLayer.runAction(cc.sequence(cc.fadeOut(0.1), cc.callFunc(function () {this.startBtn.stopAllActions();this.startBtn.scale = 1.uLayer.opacity = uLayer.active = false;}, this)));this.levelLayer.active = true;this.levelLayer.opacity = 0;this.levelLayer.runAction(cc.sequence(cc.delayTime(0.1), cc.fadeIn(0.1), cc.callFunc(function () {this.updateLevelInfo();}, this)));},//关卡界面返回回调levelBackCallBack : function(event, customEventData){if(this.curLayer == 0){return;}this.playSound(sound.BUTTON);this.curLayer = 0;this.levelLayer.runAction(cc.sequence(cc.fadeOut(0.1), cc.callFunc(function () {this.levelLayer.opacity = 255;this.levelLayer.active = false;}, this)));uLayer.active = uLayer.opacity = uLayer.runAction(cc.sequence(cc.delayTime(0.1), cc.fadeIn(0.1)));uLayerAni();},//关卡选择回调selectLevelCallBack : function(level){this.curLevel = level;if(this.curLayer == 2){return;}this.playSound(sound.BUTTON);this.curLayer = 2;this.levelLayer.runAction(cc.sequence(cc.fadeOut(0.1), cc.callFunc(function () {this.levelLayer.opacity = 255;this.levelLayer.active = false;}, this)));this.gameLayer.active = true;this.gameLayer.opacity = 0;this.gameLayer.runAction(cc.sequence(cc.delayTime(0.1), cc.callFunc(function(){ateLevelLayer(level);}, this), cc.fadeIn(0.1)));},//游戏中返回关卡界面回调backLevelCallBack : function(event, customEventData){this.clearGameData();if(this.curLayer == 1){return;}this.playSound(sound.BUTTON);this.curLayer = 1;this.gameLayer.runAction(cc.sequence(cc.fadeOut(0.1), cc.callFunc(function () {this.gameLayer.opacity = 255;this.gameLayer.active = false;}, this)));this.levelLayer.active = true;this.levelLayer.opacity = 0;this.levelLayer.runAction(cc.sequence(cc.fadeIn(0.1), cc.callFunc(function () {this.updateLevelInfo();}, this)));},//下一关按钮回调nextLevelCallBack(event, customEventData){this.playSound(sound.BUTTON);//隐藏结算界面this.gameOverLayer.active = false;this.curLevel = this.curLevel + 1;if(this.curLevel > this.allLevelCount){//已通关,返回关卡界面this.backLevelCallBack();}else{//创建新关卡ateLevelLayer(this.curLevel);}},//重置按钮回调refreshCallBack : function(event, customEventData){this.playSound(sound.BUTTON);//停止人运动动作this.gameLayer.stopAllActions();this.clearGameData();ateLevelLayer(this.curLevel);},//撤销按钮回调revokeCallBack : function(event, customEventData){//暂时没做},//创建关卡createLevelLayer : function(level){veAllChildren();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 = ateBoxItem(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 : function(row, col, type, pos){let node = new cc.Node();let sprite = node.addComponent(cc.Sprite);let button = node.addComponent(cc.Button);sprite.spriteFrame = SpriteFrame("p" + type);node.parent = this.gameControlLayer;node.position = pos;if(type == boxType.WALL){  //墙面,//墙面,命名为wall_row_colnode.name = "wall_" + row + "_" + col;node.attr({"_type_" : type});}else if(type == boxType.NONE){  //空白区域,//墙面,命名为none_row_colnode.name = "none_" + row + "_" + col;node.attr({"_type_" : type});}else{  //游戏界面,命名为land_row_colnode.name = "land_" + row + "_" + col;node.attr({"_type_" : type});node.attr({"_row_" : row});node.attr({"_col_" : col});button.interactable = true;button.target = de.on('click', this.clickCallBack, this);if(type == boxType.ENDBOX){  //在目标点上的箱子,直接将完成的箱子数加1this.finishBoxCount += 1;}}this.palace[row][col] = type;return node;},clickCallBack : function(event, customEventData){let target = event.target;//最小路径长度this.minPath = this.allCol * this.allRow + 1;//最优路线this.bestMap = [];//终点位置d = {};w  = target._row_;l = target._col_;//起点位置this.start = {};w = this.heroRow;l = this.heroCol;//判断终点类型let endType = this.d.row][l];if((endType == boxType.LAND) || (endType == boxType.BODY)){  //是空地或目标点,直接计算运动轨迹Path(this.start, 0, []);if(this.minPath <= this.allCol * this.allRow){cc.log("从起点[", w, ",", l, "]到终点[", w, ",", l, "]最短路径长为:", this.minPath, "最短路径为:");cc.log("[", w, ",", l, "]");for(let i = 0; i< this.bestMap.length;i++){cc.log("=>[",this.bestMap[i].row,",",this.bestMap[i].col,"]");}this.bestMap.unshift(this.start);this.runHero();}else{console.log("找不到路径到达");}}else if((endType == boxType.BOX) || (endType == boxType.ENDBOX)){ //是箱子,判断是否可以推动箱子//计算箱子和人物的距离let lr = w - w;let lc = l - l;if((Math.abs(lr) + Math.abs(lc)) == 1){  //箱子在人物的上下左右方位//计算推动方位是否有障碍物let nextr = w + lr;let nextc = l + lc;let t = this.palace[nextr][nextc];if(t && (t != boxType.WALL) && (t != boxType.BOX) && (t != boxType.ENDBOX)){  //前方不是障碍物,也不是墙壁,推动箱子this.playSound(sound.PUSHBOX);//人物位置还原this.setLandFrame(w, l, this.palace[w][l]);//箱子位置类型let bt = this.d.row][l];if(bt == boxType.ENDBOX){      //有目标物体的箱子类型,还原成目标点this.d.row][l] = boxType.BODY;this.finishBoxCount -= 1;}else{this.d.row][l] = boxType.LAND;}//箱子位置变成人物图,但类型保存为空地或目标点this.d.row, l, boxType.HERO);//箱子前面位置变成箱子let nt = this.palace[nextr][nextc];if(nt == boxType.BODY){  //有目标点,将箱子类型设置成有目标箱子this.palace[nextr][nextc] = boxType.ENDBOX;this.finishBoxCount += 1;}else {this.palace[nextr][nextc] = boxType.BOX;}this.setLandFrame(nextr, nextc, this.palace[nextr][nextc]);this.curStepNum += 1;//刷新步数this.setCurNum();//刷新人物位置this.heroRow = w;this.heroCol = l;this.checkGameOver();}else{this.playSound(sound.WRONG);console.log("前方有障碍物");}}else{   //目标点错误this.playSound(sound.WRONG);console.log("目标点错误");}}},//curPos记录当前坐标,step记录步数getPath : function(curPos, step, result){//判断是否到达终点if((w == w) && (l == l)){if(step < this.minPath){this.bestMap = [];for(let i = 0; i < result.length; i++){this.bestMap.push(result[i]);}this.minPath = step; //如果当前抵达步数比最小值小,则修改最小值result = [];}}//递归for(let i = (w - 1); i <= (w + 1); i++){for(let j = (l - 1); j <= (l + 1); j++){//越界跳过if((i < 0) || (i >= this.allRow) || (j < 0) || (j >= this.allCol)){continue;}if((i != w) && (j != l)){//忽略斜角continue;}else if(this.palace[i][j] && ((this.palace[i][j] == boxType.LAND) || (this.palace[i][j] == boxType.BODY))){let tmp = this.palace[i][j];this.palace[i][j] = boxType.WALL;  //标记为不可走//保存路线let r = {};r.row = l = j;result.push(r);Path(r, step + 1, result);this.palace[i][j] = tmp;  //尝试结束,取消标记result.pop();}}}},//人物运动runHero : function(){this.setLandEnable(false);let array = [];for(let i = 1; i < this.bestMap.length; i++){array.push(cc.delayTime(0.1));array.push(cc.callFunc(function(){let pos = this.bestMap[i];this.w, l, boxType.HERO);let lastPos = this.bestMap[i - 1];this.w, l, this.w][l]);this.curStepNum += 1;this.playSound(sound.MOVE);//刷新步数this.setCurNum();}, this));}array.push(cc.callFunc(function(){//刷新人物所在位置this.heroRow = w;this.heroCol = l;//设置地图是否可点击this.setLandEnable(true);}, this));if(array.length >= 2){  //避免出错this.gameLayer.runAction(cc.sequence(array));}else{this.setLandEnable(true);}},//设置地图不可点setLandEnable : function(isEnable){for(let i = 0; i < this.allRow; i++){for(let j = 0; j < this.allCol; j++){let land = this.landArrays[i][j];if(land){Component(cc.Button).interactable = isEnable;}}}},//设置地板图片setLandFrame : function(row, col, type){let land = this.landArrays[row][col];if(land){Component(cc.Sprite).spriteFrame = SpriteFrame("p" + type);land.width = this.boxW;land.height = this.boxH;}},  //游戏结束检测checkGameOver : function(){let count = this.allLevelConfig[this.curLevel].allBox;if(this.finishBoxCount == count){   //全部推到了指定位置this.gameOverLayer.active = true;this.gameOverLayer.opacity = 1; this.gameOverLayer.runAction(cc.sequence(cc.delayTime(0.5), cc.fadeIn(0.1)));//刷新完成的关卡数let finishLevel = parseInt(cc.Item("finishLevel") || 0);  //已完成关卡if(this.curLevel > finishLevel){cc.sys.localStorage.setItem("finishLevel", this.curLevel);}//刷新星星等级cc.sys.localStorage.setItem("levelStar" + this.curLevel, 3);//刷新最优步数let best = parseInt(cc.Item("levelBest" + this.curLevel) || 0);if((this.curStepNum < best) || (best == 0)){cc.sys.localStorage.setItem("levelBest" + this.curLevel, this.curStepNum);}this.playSound(sound.GAMEWIN);this.clearGameData();}},//显示关卡等级setLevel : function(){Component(cc.Label).string = this.curLevel;},//显示当前步数setCurNum : function(){Component(cc.Label).string = this.curStepNum;},//显示最优步数setBestNum : function(){let bestNum = cc.Item("levelBest" + this.curLevel) || "--";Component(cc.Label).string = bestNum;},//清理游戏中数据clearGameData : function(){this.finishBoxCount = 0;this.curStepNum = 0;this.curStepNum = 0;},//播放音效playSound : function(name){cc.loader.loadRes(name, cc.AudioClip, function (err, clip) {var audioID = cc.audioEngine.playEffect(clip, false);});},start () {},
});

感谢:

本文转载自  这篇文章,这里感谢原作者对于技术的分享。

下载:

本文章源码和资源下载地址

 

本文发布于:2024-02-02 08:31:09,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170683387042593.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:实例   cocos   creator
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23