全部文章搬運自個人我的主頁: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的方式。這個問題,留着後面查查資料再解決吧~
有任何不妥之處或錯誤歡迎各位指出,不勝感激~