最近有朋友找我用JS幫忙仿做一個別踩白塊的小遊戲程序,但他給的源代碼較麻煩,而且沒有註釋,理解起來很無力,我就以自己的想法自己做了這個小遊戲,主要是應用JS對DOM和陣列的操作。
程式思路:如圖:將遊戲區域的CSS設定為相對定位、溢出隱藏;兩塊「遊戲板」上分別排佈著24塊方格,黑色每行隨機產生一個,「遊戲板」向下方捲動並交替顯示,將每個操作板的黑塊位置存入數組,每次點擊時將數組pop出來進行比對(我覺得亮點在這裡…)。
這裡是遊戲的GitHub位址,大家可以到裡點選中部選單最右邊的Download ZIP按鈕下載到桌面一試,HTML和JS,無需伺服器。
以下是具體實現,關鍵部分有註解。
HTML部分:
<!DOCTYPE html> <html> <head><title>别踩白块</title></head> <body> <div id="gameZone"><div id="boardb" style="position: absolute;top: 0px;"></div></div>//初始化一个boardb,使ab同时存在 </body> </html>
CSS部分:
#gameZone{width: 302px;height: 602px;border: 1px solid green;margin: 20px auto;position: relative;overflow: hidden;} //遊戲區域,多兩個像素是為了除去邊框外還有足夠的300*600的空間
.square{width: 75px;height: 100px;float: left;border: 1px solid black;}
.squareBlack{width: 75px;height: 100px;border: 1px solid black;float: left;background: black;}//每個小方塊為75*100,並且設定黑色小方塊的背景色。
JS部分:
這裡分函數介紹:
全域變數初始化
var loc=600;//黑块落地失败判定 var count=0;//初始化击中黑块总数 var locArr=[];//初始化游戏板上黑块位置的 var order=(function(){ var ord="A"; return function(){ if(ord=='boarda')ord='boardb'; else ord='boarda'; return ord; } })()
//用閉包函數使每次創建的遊戲板的ID為boarda與boardb,其實用一個全域變數也行,不過為了有點逼格。 。 。
每次點選判定結果的函數
function judge(){ var num=this.id.substr(3)//获取元素的ID号 if(num!=locArr.pop()){ //与位置数组pop出的对比 clearTimeout(timer); alert("你的得分为:"+count+"分!"); return; //失败清除定时器,结算分数。 }else{ loc+=100; this.style.background="silver"; count+=1;//成功将落地标志加方格的高度,将方格背景色改变一下,击中数+1 } if(count!=0&&count%15==0){ clearTimeout(timer); newtimer=50-count/15*5; timer=setInterval('fall()',newtimer); }//每击中15个后将速度加快一点,这个式子可自行定义。 }
產生大框中小黑框位置的隨機數,每次創建遊戲板時調用此函數,根據產生數定義小黑塊的位置
function generateRand(){ var numArr=[]; for(var j=0;j<6;j++){ var num=Math.floor(Math.random()*4)+j*4; numArr.push(num); } return numArr; }
每次調用在遊戲區域的上方產生一個待往下滾動的遊戲板,並將其黑色的部分的數字PUSH進locArr中
function drawBoard(){ var temArr=generateRand();//这里应用一个临时的位置数组,为了防止两块游戏板之间的位置冲突。 locArr=temArr.concat(locArr);//将临时数组相连到全局位置数组中 var board=document.createElement('div'); board.setAttribute('id',order()); board.style.position="absolute"; board.style.top='-600px'; for(var i=0;i<24;i++){ var ele=document.createElement('div'); ele.setAttribute('id',"ele"+i); if(temArr.indexOf(i)>-1){ //判断当前创建的小方块的ID序列是否属于临时位置数组 ele.setAttribute('class','squareBlack') }else{ ele.setAttribute('class','square'); } ele.addEventListener('click',judge,false); //给每一个小方格添加点击判定函数judge board.appendChild(ele); } var gameZone=document.getElementById('gameZone'); gameZone.appendChild(board); }
找到腳本中存在的兩個遊戲板,使其往下捲動
function fall(){ gameZone=document.getElementById('gameZone'); var boarda=document.getElementById('boarda');//因为ab两个游戏板全局一直存在,所以不需要定义找不到时的逻辑 var anowtop=parseInt(boarda.style.top);//因为获取到的top位置是xxxpx类型,所以用一个parseInt()将其转换为整数便于处理。 if(anowtop==595){ //这里数目为595而不是600是因为在这一帧删除后,下一帧正好600px,刚好使两块游戏板衔接完好。 gameZone.removeChild(boarda); drawBoard();//删除游戏区域的游戏板,并在最上方新生成一个。 } anowtop+=5; boarda.style.top=anowtop+"px"; var boardb=document.getElementById('boardb'); var bnowtop=parseInt(boardb.style.top); if(bnowtop==595){ gameZone.removeChild(boardb); drawBoard(); } bnowtop+=5; boardb.style.top=bnowtop+"px"; loc-=5; if(loc==0){ clearTimeout(timer); alert("你的得分为:"+count+"分!"); return; } //每一帧将落地判定减5,当落地判定为0时表示落地,结算分数。 }
將主體呼叫寫在window.onload函數裡,讓頁面的遊戲區域載入完成後再呼叫函數。
window.onload=function(){ drawBoard(); fall(); var timer=setInterval('fall()',50); }
遊戲擴充:
增加頁面UI:因為一開始的HTML特別簡單,所以UI也很好修改,設定按鈕,點選觸發開始函數。
改變遊戲難度:修改setInterval的值,也可以對judge函數內的間隔數目進行修改,或將下落加速的表達式優化一下。
增加比分排行等:用ajax連接伺服器,在遊戲結束後將結果寫入資料庫,並引用資料中的排行榜。
改為街機模式:去定時,修改judge函數,使其每次點擊遊戲板下落一個小方格的高度。設定總數,開始計時,結束計時。