全部文章搬运自个人我的主页:sheilasun.mecss
在极客学院看到了这个游戏,在网上找到这个游戏玩了很久真的比较上瘾,因而本身也试着作了一下,能够戳这里试玩→看你有多色html
找出颜色不一样的方块jquery
界面应该至少有三个部分:git
1. 开始界面github
提示玩法,以及游戏入口canvas
2. 游戏界面api
须要提供:数组
当前剩余时间闭包
游戏设计者特地设置了一分钟的时间限制,由于这款游戏真的很很很很很耗眼睛,我费尽力气也就玩了个“超级色魔lv44”级别,眼珠子都快瞪飞了。每一分钟让眼睛能休息下很科学。app
暂停按钮
3. dialog界面
好比点了暂停会跳转到这里,这时应提供“继续游戏”按钮。
好比游戏结束了也会跳转到这里,这时应提供游戏结果,例如"经鉴定您是【瞎子lv2】",以及"再来一次"按钮。
以上的“界面”在html中能够用div实现,三个一样大小的div,position均为absolute,重叠在一块儿放置,经过隐藏或显示来完成“跳转”效果。
上面这些是大体的框架,下面梳理细节部分。
首先是游戏区的实现,是一个正方形区块,有n*n个方块,n的值由当前关卡肯定,越到后面的关卡,n值越大,要在2*2的格局中找出不一样颜色的那个,垂手可得,在9*9的格局就不那么容易了。
并且,这个“不一样颜色”的设置也有讲究,咱们把每一关中出现的两种颜色称为“普通颜色”和“不一样颜色”,如图,只有一个方块是“不一样颜色”,其余方块涂的都是“普通颜色”,找出这特殊的一个就过关了。
每关的“普通颜色”随机获取(是黑色或白色就剔除重选),“不一样颜色”就是在“普通颜色”上加点亮度,如亮度提高10%,这个提高的比例每关也有差异,越到后面值越小,越难分辨。
html以及css部分这里就不说细节了,关键的点就是:
三个界面的position要设为absolute,位置彻底重合,叠叠乐,这样只要简单的隐藏或显示就好了。
刚加载时,显示“开始界面”div,游戏开始,显示“游戏界面”,暂停或游戏结束,显示“dialog”界面,继续游戏或再玩一次,又回到“游戏界面”。
主要是说一说js部分:
其实一开始,我是想用a或span标签的,可是越到后面关卡,小方块越多,好比说9*9就能产生81个标签,这样的话,dom节点彷佛有点多啊。因而我就想用canvas,我又想代码写起来能够简便些,因而我就找上了createjs家的easeljs,说干就干,赶忙奔到createjs官网上大体看了一下用法,赶忙开工,API不会用反正能够随时回来查。下面是easeljs绘制圆的示例用法:
var stage = new createjs.Stage("demoCanvas");//参数传入canvas对象或者其id var circle = new createjs.Shape(); circle.graphics.beginFill("DeepSkyBlue").drawCircle(0, 0, 50); circle.x = 100; circle.y = 100; stage.addChild(circle); stage.update();
说个插曲,一开始我也在想是否是有必要引入createjs,后来我忽然想起来我在网上玩这个游戏的时候,彷佛看到别人的方块都是圆角的,比不加圆角好看好多,我,也想这么作。可是依稀记得canvas彷佛并无现成的画圆角矩形的方法,难道我要用arc加line去拼合?还有,我还得为那个特殊的小方块添加点击事件呢,若是就用原生的api,我须要这样作:
这太麻烦了,而用createjs的话,我能够直接使用drawRoundRectangle方法,我还能够在画小方块的时候就给它(仅给它)绑上click事件,特别方便。
前面说过,难度的增长是经过增长"小方块的个数"和减小"不一样颜色相对普通颜色增长的亮度比例",那么如何反映到代码上呢?
能够用一个数组保存每关的每行小方块个数(列方向上也是这个数),如:
var levs= [2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9]
这样每关的小方块总数就分别是:2*2,3*3,4*4,4*4......
每次要画小方块的时候,就从这个数组里取值,如第三关就是每行levs[2]个,每列也是levs[2]个,即共4*4个。
... drawRects:function() { gameView.removeAllChildren();//移除上次绘制 var num = this.levs[this.curLev];//当前关卡每行列应有的方块数 //计算每一个小方块的宽度,全部小方块宽度加上两两之间的间隔构成整个stage(绘制舞台)的宽度 var width = (stage.canvas.width - gap * (num - 1)) / num; var height = (stage.canvas.height - gap * (num - 1)) / num; var color = randomColor();//获取随机色 var pickedX = _randomPick(0, num - 1);//随机指定特殊方块的位置 var pickedY = _randomPick(0, num - 1); for (var i = 0; i < num; i++) { for (var j = 0; j < num; j++) { var rec; if (i === pickedX && j === pickedY) { rec = new Rectangle(width, height, color, .5, Rectangle.TYPE_PICKED);//建立特殊方块 (function (me) { rec.addEventListener('click', function () { me.nextLevel();//进入下一关 }) })(this);//注意闭包 } else { rec = new Rectangle(width, height, color, .5, Rectangle.TYPE_NORMAL);//建立普通方块 } gameView.addChild(rec); rec.x = (width + gap) * i;//偏移&&铺开 rec.y = (height + gap) * j; } } } ...
须要注意添加监听事件的地方,一开始写的时候没注意直接用的this.nextLevel(),直接去window对象上找了,结果nextLevel方法天然是undefined。解决的办法是建立一个当即执行函数,传入this。
那么如何设置亮度提高比例呢?
固然也能够用相似上面的方法,用另外一个数组保存这些比例。可是我不想写那么死,仍是用一个函数实现吧:
在20%与60%间取值。
... getLightenRatio: function () { //由当前关卡数获取亮度增长比例 var minValue = 0.2, maxValue = 0.6; return maxValue - (maxValue - minValue) / (this.levs.length - 1) * this.curLev; } ...
关于得分这里我都是作的简单处理,过一关则加一分。
关于结束方式,由于这个游戏里没有僵尸没有炸弹,惟一的结束方式就只能是时间用完啦。
关于鉴定级别,如咱们玩的时候看到的“色狼lv23”是如何获得的呢?
仍是定义一个数组,保存了这些级别的名称。
var title=["瞎子", "色盲", "色郎", "色狼", "色鬼", "色魔", "超级色魔", "变态色魔", "孤独求色"];
显示游戏结果的时候,就是从这个数组里取出某值,具体取哪一个值,就看本身定义的规则了。
好比说,我认为得分15分或如下的基本就算瞎子了,以后每加五分晋级一次,好比15分对应“瞎子”,16-20分对应“色盲”,21-25对应“色狼”,以此类推下去。
惟一须要注意的就是边界控制,不要超出数组最大索引。
用一个变量保存剩余时间leftTime,缺省值是60,即一分钟后游戏结束.
若是没有暂停功能,那么处理起来很简单,游戏刚进入时,初始化计时器,一秒tick一次,只要在计时器的tick事件里递减这个leftTime便可,当leftTime小于0,结束。
但加入暂停功能也不麻烦,只要手动设置一个标记isPaused,在tick事件的最开始判断这个标记的值,false则执行事件的递减。暂停按钮的点击便是改变这个变量的值为true,继续游戏按钮的点击便是改变其为false。
... pause: function () { //暂停游戏 this.isPaused = true; }, resume: function () { //继续游戏 this.isPaused = false; }, ...
tick事件内部:
if (!me.isPaused) { --me.leftTime; if (me.leftTime === 0) { me.gameover(); } }
应该回到游戏界面并将环境重置,因此以前的代码中应该提供一个reset方法,这里调用这个方法便可。
好了,这样下来,整个游戏差很少就完成了,仍是戳这里能够玩~→看你有多色
戳这里有代码~→github-sheila1227,代码遵循AMD规范,入口文件以下:
<script src="http://libs.tan14.net/require.js/2.1.14/require.min.js" data-main="js/app.js"></script>
入口文件中作一下配置:
requirejs.config({ "baseUrl": "./js", "paths": { "app": "app", "jquery": "//libs.baidu.com/jquery/2.0.0/jquery.min" ,//结尾不要加.js扩展名 "createjs": "easeljs.min" } }); // Load the welcome module to start the app requirejs(["welcome"], function(welcome) { welcome.init('.page-welcome.page'); });
这里有个问题是,由于jQuery支持AMD,因此我能够直接require,可是createjs不支持AMD,因此我直接用script标签直接引入,但我感受是否是应该用define包一下,让它也能够支持requirejs的方式。这个问题,留着后面查查资料再解决吧~
有任何不妥之处或错误欢迎各位指出,不胜感激~