上週五忽然接到一個重磅消息:公司決定開發首款手機小遊戲,運行平臺是淘寶app上的微淘平臺。這個微淘平臺從技術上講是一個能運行html5的平臺,跟微信比較相似。接到這樣的任務,我天然很高興呀,由於這也是個人第一款手機遊戲了。通過一個週末的奮戰,算是初步把這個遊戲跑起來了。在寫以前我也是查看了很多算法和實際線上代碼,由於這都是個被寫爛了的遊戲了,那麼你只要百度一下‘連連看算法’的話你基本都不用本身寫了,算法也有好幾種,一開始我也比較迷惑,不知道從何下手,通過幾番比較,我仍是選擇了本身的一種簡單算法,若是跟你或者跟你看到的算法有雷同,那麼只能說我看到過的連連看算法仍是太少了。不過我這個算法並無確保開局的科學性,也就是沒有對開局有深度計算確保這個連連看是可玩的,可是由於在7*7=49個方格子上只有20個圖片,按照這個疏密程度來看的話,開局不可解的狀況是至關少的,我本身測了過百次也沒有遇到這樣的狀況。好了咱們開始吧!!!javascript
先看一下游戲的界面:一點擊開始,遊戲就開始計時,頂部的折扣會飛速上升,若是玩家玩的速度太慢的話那麼只能拿到一個他都不想要的折扣了,呵呵html
<img src="png0.jpg" id="png0"/><img src="png1.jpg" id="png1"/><img src="png2.jpg" id="png2"/><img src="png3.jpg" id="png3"/><img src="png4.jpg" id="png4"/> <img src="png5.jpg" id="png5"/><img src="png6.jpg" id="png6"/><img src="png7.jpg" id="png7"/><img src="png8.jpg" id="png8"/><img src="png9.jpg" id="png9"/> <img src="head.jpg" id="head"/> <div id="main"> <canvas id="gameHead"></canvas> <canvas id="gameBody"></canvas> <div id="startGame"><span>開始</span></div> </div>
這段算是最主要的html代碼。你看到的頂部的那10張圖片是display:none掉的,我之因此放是由於,在js裏面,我須要在一個數組裏面存放這十個圖片的原生對象,那麼爲了早點下載這個圖片呢,我但願他們隨着html一塊兒下載,而不是到時候經過var img = new Image();img.src='png0.png'這種形式來加載,方便加快遊戲加載速度。這個#main是遊戲的主題,裏面存放了兩個canvas,第一個canvas用於寫當前折扣,下面一個canvas纔是玩遊戲的主場。下面咱們着重講javascript部分:html5
var gridW = document.width / 7;//每個格子的寬度,根據屏幕的寬度來定,作到自適應 var gridH = document.width / 7; var get = function(str){ return document.getElementById(str); }; var pngs; var leftPair = 10; var nums = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10];//此數組用於隨機的佈局20張圖片,圖片只有10種,每種2張,到時候逐一取出數字來,再從pngs這個數組上取出圖片對象 var Darray = [];//這個過重要了,這個是一個7*7的二維數組,經過這個數組,我可以知道在某一點上有沒有物體,以及兩個物體是否是同一個物體,這樣才能判斷我需不須要對兩個物體進行消除計算,他的初始化在下方 var gameStart = false;//遊戲有沒有開始的標記,false表示不能開始,點擊無效 var canvas = document.getElementById("gameBody"); var canvas_x = canvas.offsetLeft;//遊戲canvas距離屏幕左邊的距離 var canvas_y = canvas.offsetTop; var cxt = canvas.getContext('2d'); window.onload = function(){ pngs = [get('png0'), get('png1'), get('png2'), get('png3'), get('png4'), get('png5'), get('png6'), get('png7'), get('png8'), get('png9')];//圖片都加載好之後我就把圖片對象保存到這個pngs對象上 pngs = pngs.concat(pngs);//須要20張圖片,那麼我就再經過concat方法複製一遍這個pngs timing('0.0折');//遊戲未開始時先設置爲0.0折 layout();//作好佈局,此時還不能玩,只是佈局好看看 get('startGame').addEventListener('click',function(e){//點擊開始這個大按鈕開始計時,gameStart也變爲true timing(); gameStart = true; this.style.display = 'none'; e.stopPropagation(); }); } function layout(){//layout這個函數呢,就是首先生成一個7*7的二維數組,再進行圖片的隨機佈局,咱們接着看 for(var i = 0 ; i < 7 ; i ++){ Darray[i] = [0, 0, 0, 0, 0, 0, 0]; } while(nums.length){//只要nums這個數組還有長度,就說明尚未佈局好,nums這個數組是佈局一張圖片減小一個數組項的 var _ = Math.floor(Math.random() * 7 + 0);//這兩部隨機生成一個橫座標和縱座標來隨機決定在哪一個坑上放圖片 var $ = Math.floor(Math.random() * 7 + 0); if(! Darray[_][$]){//若是這個坑上尚未圖片,那就放上去,而且把nums shift掉一個 Darray[_][$] = nums.shift(); cxt.drawImage(pngs[Darray[_][$] - 1] , $ * gridW , _ * gridH , gridW , gridH); } } } window.coor_1 = null;//這兩個玩意重要了,他們是當前被點擊的兩張圖片的經紀人,到時候就根據他兩來決定要不要進一步的消除算法 window.coor_2 = null; /*下面這段要好好講一下,這裏存在一個兼容性問題,就在昨天下班前,document.body這個位置仍是canvas,在不太老的安卓機器上跑得很順暢,可是在安卓2.3或者更老的機器上,出現這樣一個問題:點擊canvas就會出現一個透明框,一個不太敢肯定的原///因是,安卓2.3上的html5 canvas一旦監聽click事件,一點擊就出現這個透明框,用其餘的好比touchstart之類的事件是沒有問題的,找來找去沒找到方案,最好主管提示我能夠把事件綁定在全局上,那麼稍做修改,也能跑,而且老安卓也ok了。*/ document.body.addEventListener('click' , function(e){ if(!gameStart){ return; } var coor_x = Math.floor((e.pageY-canvas.offsetTop) / gridW); var coor_y = Math.floor(e.pageX / gridW); if(! Darray[coor_x][coor_y]){ return; } if(! window.coor_1){ window.coor_1 = [coor_x, coor_y]; drawRect(window.coor_1); }else{ window.coor_2 = [coor_x, coor_y]; if(Darray[window.coor_1[0]][window.coor_1[1]] != Darray[window.coor_2[0]][window.coor_2[1]] || window.coor_1.join(';') == window.coor_2.join(';')){ cleanRect(window.coor_1); window.coor_1 = null; window.coor_2 = null; return; }else if(window.coor_1 && window.coor_2){ zeroCorner(window.coor_1 , window.coor_2 , true); } } e.stopPropagation(); } , false); function zeroCorner(coor_1 , coor_2 , next){ if(coor_1[0] != coor_2[0] && coor_1[1] != coor_2[1]){ oneCorner(coor_1 , coor_2 , true); return; } if(coor_1[0] == coor_2[0]){ var start = Math.min(coor_1[1] , coor_2[1]) + 1; var end = Math.max(coor_1[1] , coor_2[1]); var arr = Darray[coor_1[0]].slice(start , end); if(! Math.max.apply(null , arr) || ! arr.length){ if(next){ clear(coor_1 , coor_2); }else{ return true; } }else if(next){ oneCorner(coor_1 , coor_2 , true); } }else if(coor_1[1] == coor_2[1]){ var satrt = Math.min(coor_1[0] , coor_2[0]) + 1; var end = Math.max(coor_1[0] , coor_2[0]); var arr = []; for(var i = satrt ; i < end ; i ++){ arr.push(Darray[i][coor_1[1]]); } if(! Math.max.apply(null , arr) || ! arr.length){//若是最大值是0或者二者是隔壁,說明此路可走 if(next){ clear(coor_1 , coor_2); }else{ return true; } }else if(next){ oneCorner(coor_1 , coor_2 , true); } } } function oneCorner(coor_1 , coor_2 , next){ var Diagonal_1 = [coor_2[0], coor_1[1]]; var Diagonal_2 = [coor_1[0], coor_2[1]]; if(! Darray[Diagonal_1[0]][Diagonal_1[1]] && zeroCorner(Diagonal_1 , coor_1 , false) && zeroCorner(Diagonal_1 , coor_2 , false)){/*若是行得通*/ if(next){ clear(coor_1 , coor_2); }else{ return true; } }else if(! Darray[Diagonal_2[0]][Diagonal_2[1]] && zeroCorner(Diagonal_2 , coor_1 , false) && zeroCorner(Diagonal_2 , coor_2 , false)){ if(next){ clear(coor_1 , coor_2); }else{ return true; } }else if(next){ twoCorner(coor_1 , coor_2); } } function twoCorner(coor_1 , coor_2){ var coor_1_y = coor_1[0]; var coor_1_x = coor_1[1]; var coor_2_y = coor_2[0]; var coor_2_x = coor_2[1]; var coor_1_arr = [ [coor_1_y, 0], [coor_1_y, 1], [coor_1_y, 2], [coor_1_y, 3], [coor_1_y, 4], [coor_1_y, 5], [coor_1_y, 6], [0, coor_1_x], [1, coor_1_x], [2, coor_1_x], [3, coor_1_x], [4, coor_1_x], [5, coor_1_x], [6, coor_1_x] ]; var coor_2_arr = [ [coor_2_y, 0], [coor_2_y, 1], [coor_2_y, 2], [coor_2_y, 3], [coor_2_y, 4], [coor_2_y, 5], [coor_2_y, 6], [0, coor_2_x], [1, coor_2_x], [2, coor_2_x], [3, coor_2_x], [4, coor_2_x], [5, coor_2_x], [6, coor_2_x] ]; for(var i = 0 , len = coor_1_arr.length ; i < len ; i ++){ if(Darray[coor_1_arr[i][0]][coor_1_arr[i][1]]){ continue; } if(oneCorner(coor_1_arr[i] , coor_2 , false) && zeroCorner(coor_1_arr[i] , coor_1 , false)){ clear(coor_1 , coor_2); return; } } for(var i = 0 ; i < coor_2_arr.length ; i ++){ if(Darray[coor_2_arr[i][0]][coor_2_arr[i][1]]){ continue; } if(oneCorner(coor_2_arr[i] , coor_1 , false) && zeroCorner(coor_2_arr[i] , coor_2 , false)){ clear(coor_1 , coor_2); return; } } cleanRect(window.coor_1); window.coor_1 = null; window.coor_2 = null; } function clear(coor_1 , coor_2){ cxt.clearRect(coor_1[1] * gridW , coor_1[0] * gridH , gridW , gridH); cxt.clearRect(coor_2[1] * gridW , coor_2[0] * gridH , gridW , gridH); Darray[coor_1[0]][coor_1[1]] = 0; Darray[coor_2[0]][coor_2[1]] = 0; window.coor_1 = null; window.coor_2 = null; leftPair --; if(! leftPair){ clearInterval(window.timingInterval); gameStart = false; document.getElementById('finish').style.display = 'block'; } } function drawRect(coor){ cxt.save(); cxt.lineWidth = 4; cxt.strokeStyle = '#f27b04'; cxt.lineJoin = 'round'; cxt.strokeRect(coor[1] * gridW + 3 , coor[0] * gridH + 3 , gridW - 6 , gridH - 6); cxt.restore(); } function cleanRect(coor_1){ cxt.drawImage(pngs[Darray[coor_1[0]][coor_1[1]] - 1] , coor_1[1] * gridW , coor_1[0] * gridH , gridW , gridH); } var canvas_timing = get('gameHead'); var cxt_timing = canvas_timing.getContext('2d'); function timing(str){ cxt_timing.clearRect(0 , 0 , canvas_timing.width , canvas_timing.height); cxt_timing.font = '40px impact'; cxt_timing.fillStyle = 'red'; cxt_timing.textAlign = 'center'; cxt_timing.textBaseline="middle"; if(str){ cxt_timing.fillText(str,canvas_timing.width/2,canvas_timing.height/2); return; } var step = 0.05; var discount = 0; window.timingInterval = setInterval(function(){ cxt_timing.clearRect(0 , 0 , canvas_timing.width , canvas_timing.height); cxt_timing.fillText(discount.toFixed(2) + '折',canvas_timing.width/2,canvas_timing.height/2); discount = discount + step; if(discount >= 10){ discount = 10; clearInterval(window.timingInterval); } } , 80); } get('playAgain').addEventListener('click', function () { window.coor_1 = null; window.coor_2 = null; nums = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10]; leftPair = 10; layout(); get('startGame').style.display = 'block'; document.getElementById('finish').style.display = 'none'; });