2048在一个4X4的方阵中,玩家需要滑动上面的数字,如果俩个数字相邻并且相等,则相加,需要达到2048,方可胜利。

因为在浏览器操作,所以此例的操作方法为:键盘上的w,s,a,d代表上下左右,也可用小键盘左边的上下左右键。

下面给一张游戏截图,也可以点击这里进行试玩:)

IDE:webstorm

好,现在开始讲解我的制作过程。

首先,新建一个项目,名字叫mini2048。我是用终端cocos new Project出来的,所以要删除一些不必要的代码,并且添加一些游戏相关的资源。

因为这个游戏主要是用做demo并且分享制作过程,所以美术啥的也没好好搞,就一个标题的2048字体用了外部的fnt资源。大家粗略看看就行~

添加游戏背景

        /*一个灰色的背景和白色的线组成的方格*/
var background = new cc.LayerColor(cc.color(180,170,160,255),size.width,size.height); //灰色背景
this.addChild(background,0);
var draw = cc.DrawNode.create();
this.addChild(draw, 1);
for(var index=0; index<5; index++){
draw.drawSegment(cc.p(40+index*60, 20), cc.p(40+index*60, 260), 1, cc.color(255, 255, 255, 255)); //竖线
draw.drawSegment(cc.p(40, 20+index*60), cc.p(280, 20+index*60), 1, cc.color(255, 255, 255, 255)); //横线
}

再继续添加一些界面元素,标题,得分,重新游戏什么的

        //标题
var title = cc.LabelBMFont.create("2 0 4 8", res.LabelFont_Fnt);
title.x = size.width/2;
title.y = size.height-40;
this.addChild(title,1); //得分
var scoreLabelText = cc.LabelTTF.create("score","Scissor Cuts",20);
scoreLabelText.x = 60;
scoreLabelText.y = size.height*4/5;
scoreLabelText.setColor(cc.color(0,0,0,255));
this.addChild(scoreLabelText,1);
this.scoreLabel = cc.LabelTTF.create("0","Scissor Cuts",20);
this.scoreLabel.x = 60;
this.scoreLabel.y = size.height*4/5-25;
this.scoreLabel.setColor(cc.color(0,0,0));
this.addChild(this.scoreLabel,1); //重新游戏
cc.MenuItemFont.setFontName("Arial");
var restartItem = cc.MenuItemFont.create("restart", this.restartGame, this);
restartItem.setColor(cc.color(22,100,255));
restartItem.x = size.width - 60;
restartItem.y = size.height*4/5-12.5;
var restartMenu = cc.Menu.create(restartItem);
restartMenu.x = 0;
restartMenu.y = 0;
this.addChild(restartMenu,1); //结束label
var gameOverLabel = cc.LabelTTF.create(" 游戏结束! ","Scissor Cuts",50);
gameOverLabel.setColor(cc.color(255,0,255));
gameOverLabel.x = size.width/2;
gameOverLabel.y = size.height/2+60;
gameOverLabel.visible = false;
this.addChild(gameOverLabel,11,5); //通关label
var passTheGameLabel = cc.LabelTTF.create(" 恭喜通关!","Scissor Cuts",50);
passTheGameLabel.setColor(cc.color(255,255,0));
passTheGameLabel.x = size.width/2;
passTheGameLabel.y = size.height/2+60;
passTheGameLabel.visible = false;
this.addChild(passTheGameLabel,11,6);

随后添加键盘事件来相应w,s,a,d和小键盘旁上下左右键的操作。

        if (cc.sys.capabilities.hasOwnProperty('keyboard'))
cc.eventManager.addListener({
event: cc.EventListener.KEYBOARD,
onKeyReleased:function (key, event) {
if(key==[cc.KEY.w] || key==[cc.KEY.up] ){
event.getCurrentTarget().slideUp(); //向上滑
}
else if(key==[cc.KEY.a] || key==[cc.KEY.left] ){
event.getCurrentTarget().slideLeft(); //向左滑
}
else if(key==[cc.KEY.d] || key==[cc.KEY.right] ){
event.getCurrentTarget().slideRight(); //向右滑
}
else if(key==[cc.KEY.s] || key==[cc.KEY.down] ){
event.getCurrentTarget().slideDown(); //向下滑
}
}
}, this);

然后制作Card类,继承cc.Sprite,用来做游戏中的卡片。我这里的逻辑是这样的,游戏开始前,初始化4X4的16张卡片,并且每张卡片在对应的位置,并且卡片数字都设置为0,

当游戏运作的时候,不移动卡片,只改变对应卡片上的数字,并且对改变后的数字进行判断,如果是0,则隐藏数字,如果是>0的值,则显示数字并根据值来对数字进行美化。

        this.backgroundPic = new cc.LayerColor(cc.color(0, 0, 255, 111), 50, 50); //卡片底色
this.labelText = cc.LabelTTF.create("0", "Trebuchet MS", 21); //卡片数字
this.backgroundPic.ignoreAnchorPointForPosition(false);
this.addChild(this.backgroundPic, 0);
this.addChild(this.labelText,1);

并且给Card类添加一些方法,如设置卡片数字,获取卡片数字的值,对卡片数字大小和卡片背景进行美化等等,因为这些比较简单,所以就不贴码了,尽量避免此博文显得过于冗长。

下面介绍下2048的算法,我觉得也是这部游戏唯一的难点~

因为游戏是上下左右进行滑动,所以只要知道一个方向上是如何运作的,那么也就可以举一反三了,譬如向左滑动这个操作,再对其进行剖析,

我们会发现算法对4排上的数字都是进行同样的操作,所以我们只研究一行数字的算法就可以了。其他的只要循环3次就行。

/*因为算法比较简单,所以我就用注释解释下*/
for(var y=0; y<4; y++){
for(var x=0; x<4; x++){
for(var xRight=x+1; xRight<4; xRight++){
if(game2048array[xRight][y].getCardNumber() != 0){ //game2048array是存放16张卡片的数组,y代表某一行,如果对应卡片右边的卡片数值为0,则对下一个右边的卡片进行循环判断
if(game2048array[x][y].getCardNumber() == 0){ //如果对应卡片右边的值不为0,并且对应卡片的值为0,则将对应卡片的值改为其右边卡片的值
game2048array[x][y].setCardNumber(game2048array[xRight][y].getCardNumber());
game2048array[xRight][y].setCardNumber(0); //然后设置其右边卡片的值为0
this.zeroCardIndex.removeZeroCard(x,y); //this.zeroCardIndex是一个存放值为0的卡片的数组,后面会用到
this.zeroCardIndex.push({coordX:xRight,coordY:y});
x--;
}
else if(game2048array[x][y].getCardNumber() == game2048array[xRight][y].getCardNumber()){
game2048array[x][y].setCardNumber(game2048array[x][y].getCardNumber()*2); //如果对应卡片右边的值不为0,并且对应卡片的值和其右边卡片的值相等,则对应卡片的值位置为原来的两倍
game2048array[xRight][y].setCardNumber(0); //同样设置其右边卡片的值为0
if(game2048array[x][y].getCardNumber()==2048){ //进行判断,如果对应卡片的值达到2048,则游戏通关
this.gameStop = true;
this.passGameLabelAppear(); //通关
}
else{
this.zeroCardIndex.push({coordX:xRight,coordY:y});
}
}
break; //如果对应卡片其右边的卡片值非0,并且对应卡片的值和其右边卡片的值不相等,那么跳出此轮循环,继续判断下一个卡片
}
}
}
}

OK,2048的核心算法已经充分展示,接着,每滑动一次就需要添加一张值为2或者4的卡片。我是这么做的,把游戏中非0卡片的位置都记录到一个数组this.zeroCardIndex中,然后每一次滑动后在此数组中随机取一个元素,

并且在元素上对应的位置信息上添加2或者4的数字。看代码

    addOneCard:function(){
var cardIndex = parseInt(Math.random()*this.zeroCardIndex.length); //随机获取一张值为0的卡片
var card = game2048array[this.zeroCardIndex[cardIndex].coordX][this.zeroCardIndex[cardIndex].coordY]; //获取对应位置信息上的卡片
card.setCardNumber(Math.random()<0.2?4:2); //给卡片设置数字 20%的几率会随机到4的卡片
this.zeroCardIndex.splice(cardIndex, 1); //从数组中删除此张卡片
},

最后,对游戏“死亡”进行判定,首先对卡片0的数组的长度(this.zeroCardIndex.lenght)进行判断,如果为0,则判断横向或者竖向的数字,俩俩是不是都不相同,如果是,则表示游戏结束。

    isGameOver:function(){
for(var x=0;x<4;x++){
for(var y=0;y<4;y++){
if(x<3 && (game2048array[x][y].getCardNumber()==game2048array[x+1][y].getCardNumber())){ //横向俩俩判断
return false;
}
if(y<3 && (game2048array[x][y].getCardNumber()==game2048array[x][y+1].getCardNumber())){ //竖向俩俩判断
return false;
}
}
}
return true;
}

OK!至此,2048的基本游戏逻辑都介绍完毕,剩下的譬如分数累加什么的简单逻辑就不罗列了,第一次写博客教程,大家多多包涵,有不合适的地方尽管吐槽砸墙!

希望每一个游戏人都能实现自己的游戏梦!:)

【cocos2d-js 3.0】制作2048的更多相关文章

  1. cocos2d js ClippingNode 制作标题闪亮特效

    1.效果图: 之前在<Android 高仿 IOS7 IPhone 解锁 Slide To Unlock>中制作了文字上闪亮移动的效果,这次我们来看下怎样在cocos2d js 中做出类似 ...

  2. 【翻译】Ext JS 5.0.1 中的新功能

    原文:What's New in Ext JS 5.0.1 今天,我们很高兴的宣布Ext JS 5.0.1发布了!此维护版本基于Sencha社区的反馈做了一些改进.下面让我们来了解一下这些改变. 可访 ...

  3. (15)如何使用Cocos2d-x 3.0制作基于tilemap的游戏:第三部分(完)

    引言 程序截图: 在第二部分教程中,Ray教大家如何在地图中制作可碰撞的区域,如何使用tile属性,如何制作可以拾取的物品以及如何动态修改地图.如何使用“Heads up display”来显示分数. ...

  4. (14)如何使用Cocos2d-x 3.0制作基于tilemap的游戏:第二部分

    引言 程序截图: 这篇教程是<如何使用Cocos2d-x 3.0制作基于tilemap的游戏>的第二部分.在上一个教程中,我们创建了一个简单的基于tiled地图的游戏,里面有一个忍者在沙漠 ...

  5. (13)如何使用Cocos2d-x 3.0制作基于tilemap的游戏:第一部分

    引言 程序截图: 本教程将会教大家如何使用Cocos2d-x来做一个基于tile地图的游戏,当然还有Tiled地图编辑器.(我们小时候玩的小霸王小学机里面的游戏,大部分都是基于tile地图的游戏,如坦 ...

  6. cocos2d js jsb XMLHttpRequest 中文乱码

    1.首先讲下怎样使用XMLHttpRequest 下面所说的是在cocos2d-x 2.2.2 或者 2.3 版本号中. 首先要明确cocos2d js事实上分两个版本号,一个是html5的版本号,另 ...

  7. 更轻更快的Vue.js 2.0与其他框架对比(转)

    更轻更快的Vue.js 2.0 崭露头角的JavaScript框架Vue.js 2.0版本已经发布,在狂热的JavaScript世界里带来了让人耳目一新的变化. Vue创建者尤雨溪称,Vue 2.0  ...

  8. js傻瓜式制作电子时钟

    js傻瓜式制作电子时间 使用到的知识点 setInterval函数 构建函数new Date if判断 demo: //css样式请自行设置 <span id="timer" ...

  9. 窥探Vue.js 2.0 - Virtual DOM到底是个什么鬼?

    引言 你可能听说在Vue.js 2.0已经发布,并且在其中新添加如了一些新功能.其中一个功能就是"Virtual DOM". Virtual DOM是什么 在之前,React和Em ...

  10. 窥探Vue.js 2.0

    title: 窥探Vue.js2.0 date: 2016-09-27 10:22:34 tags: vue category: 技术总结 --- 窥探Vue.js2.0 令人兴奋的Vue.js 2. ...

随机推荐

  1. QSQL导出mapfile和mapfile中PostGIS连接的一点心得

    昨天弄QSQL导出mapfile,一直遇到下图的错误 原因是QGIS在渲染图层时候使用了新的符号,在图层上右键-属性,如下图将符号修改就OK了 然后我尝试使用QGIS连接本机PostGIS数据,结果老 ...

  2. 了解OData(一)

    了解OData(一) 最近做了一个小项目,其中用到了 WCF Data Service,之前是叫 ADO.NET Data Service 的.关于WCF Data Service,博客园里的介绍并不 ...

  3. js区分汉字和字符,校验长度

    遇到这么一个问题,    长度限制输入150个英文字符(小于等于150个英文字符长度),超出则直接禁止输入,并提醒:摘要输入必须小于等于75个中文字符长度! 长度校验倒是没问题,但是要区分汉字还是英文 ...

  4. Python 函数简介 之二

    1.当函数有多个返回值时, 其多个返回值将以元组的形式出现 def test1(): print("in the test1") return 'end' def test2(): ...

  5. 【Spring】基于注解的实现SpringMVC+MySQL

    目录结构: // contents structure [-] SprinigMVC是什么 SpringMVC工作原理 @Controller和@RequestMapping注解 @Controlle ...

  6. HTML <dl> 标签

    <html><body><h2>一个定义列表:</h2><dl>   <dt>计算机</dt>   <dd&g ...

  7. 【CentOS如何最小化安装】

    近来发现越来越多的运维小伙伴们都有最小化安装系统的洁癖,因此,找老男孩来咨询,这个"洁癖"好习惯啊,必须支持,,因此发布本文和大家分享下. (1)系统安装类型选择及自定义额外包组 ...

  8. iOS strong与weak的使用

    strong修饰的属性是强指针类型的,weak修饰的属性是弱指针类型的 ARC对于内存中的对象管理机制,当某个对象没有被强指针指向的时候,该对象就会被销毁. 所以不适当的使用strong和weak修饰 ...

  9. ecshop3.0.0注入

    配个环境来演示给别人看..分析一下.flow.php文件缺陷,order_id在post请求没有单引号保护.造成注入 <?php elseif ($_REQUEST['step'] == 're ...

  10. [kuangbin带你飞]专题六 最小生成树 POJ 2421 Constructing Roads

    给一个n个点的完全图 再给你m条道路已经修好 问你还需要修多长的路才能让所有村子互通 将给的m个点的路重新加权值为零的边到边集里 然后求最小生成树 #include<cstdio> #in ...