先聲明哈:我做的這個也是跟著被人學(xué)習(xí)的,寫文章是為了復(fù)習(xí)思路,還有鞏固一下。總而言之呢,就是為了多理解思路,多折騰代碼。
咳咳,上次我們已經(jīng)將游戲的初始化全部完成了,包括游戲過程中需要的updataBoardView(); generateOneNumber();showNumberWithAnimation()也都全寫好了,所以這次呢就是來寫游戲過程中的邏輯了,發(fā)車了,抓緊時間上車~~
一.游戲過程鍵盤操作
- 鍵盤監(jiān)聽函數(shù)
玩過這款游戲的人都知道,操作就是通過上下左右來移動小方塊,完成合并操作。所以我們在全局寫一個鍵盤的事件監(jiān)聽函數(shù)$(document).keydown()。
我們需要在其中寫入什么呢?首先需要判斷是哪個按鍵被按下,所以肯定需要獲取event這個事件觸發(fā)式生成的對象
Event 對象
Event 對象代表事件的狀態(tài),比如事件在其中發(fā)生的元素、鍵盤按鍵的狀態(tài)、鼠的位置、鼠標(biāo)按鈕的狀態(tài)。
事件通常與函數(shù)結(jié)合使用,函數(shù)不會在事件發(fā)生前被執(zhí)行!
具體的event的解釋大家可以去w3school看看。其中event有一個keyCode屬性能夠獲取到敲擊鍵盤的虛擬鍵盤碼
我們通過拿到的keyCode來判斷哪個鍵被按下,同時執(zhí)行相應(yīng)的函數(shù)就好了,代碼如下
$(document).keydown(function (event){
switch(event.keyCode){
case 37: //left
moveLeft();
generateOneNumber();
break;
case 38: //up
break;
case 39: //right
break;
case 40: //down
break;
}
});
但這牽扯到的兩個問題,一個是當(dāng)前的游戲狀態(tài)允不允許執(zhí)行左移或者右移,比如如果是不能左移的話,那按下←應(yīng)該是無效的,同時就不應(yīng)該新生成一個數(shù)字。一個是移動后應(yīng)該立馬檢測游戲有沒有結(jié)束,如果四個方向都不能移動的話,游戲就應(yīng)該GameOver了。為解決第一個問題,我們需要做一個檢測,返回一個值來決定需不需要新生成一個數(shù)字。為解決第二個問題,我們需要寫一個isgameover().
- 我們將檢測函數(shù)寫在moveleft內(nèi)部返回,將鍵盤監(jiān)聽代碼改為如下
case 37://left
if(moveLeft()){
generateOneNumber();
isgameover();
}
- 左移函數(shù)moveLeft()
在這里面我們做兩件事,一個是先判斷能不能移動,不行的話直接返回false。如果能移動的話,我們再執(zhí)行接下來的移動部分。我先把代碼貼出來
完整代碼:
function moveLeft(){
if(!canMoveLeft(board)){
return false;
}
//遍歷右邊12個格子
for(var i=0;i<4;i++){
for(var j=1;j<4;j++){
if(board[i][j]!=0){
//有數(shù)字則遍歷左邊
for(var k=0;k<j;k++){
//看落點是否為空且路上有無障礙
if(board[i][k]==0&&noBlockHorizontal(i,k,j,board)){
//move
showMoveAnimation(i,j,i,k);
//更新
board[i][k]=board[i][j];
board[i][j]=0;
continue;
}else if(board[i][k]==board[i][j]&&noBlockHorizontal(i,k,j,board)&&!hasConflicted[i][k]){
//move
showMoveAnimation(i,j,i,k);
//更新
board[i][k]+=board[i][j];
board[i][j]=0;
//分?jǐn)?shù)增加
score += board[i][k];
updateScore(score);
hasConflicted[i][k]=true;
continue;
}
}
}
}
}
//遍歷完后更新格子顯示狀態(tài),慢一點才能顯示動畫
setTimeout("updateBoardView()",200);
return true;
}
我們通過canMoveLeft來判斷當(dāng)前游戲狀態(tài)能不能左移,我們要用到的是存儲格子數(shù)據(jù)的數(shù)組board,我們將這個函數(shù)寫在support.js中
//檢測能否左移
function canMoveLeft(board){
for(var i=0;i<4;i++){
for(var j=1;j<4;j++){
if(board[i][j]!= 0){
if(board[i][j-1]==0||board[i][j-1]==board[i][j])
return true;
}
}
}
return false;
}
這里面顯而易見的是左邊第一列的4個格子是不能移動的,所以只需要遍歷右邊的12個格子,只要有一個有數(shù)字的格子的自身左邊的一個格子為空,或者說值和它相等,那么游戲狀態(tài)就是可以左移的,直接return true;即可。
看完檢測函數(shù)后我們來看看后面的移動的部分。
//遍歷右邊12個格子
for(var i=0;i<4;i++){
for(var j=1;j<4;j++){
if(board[i][j]!=0){
//有數(shù)字則遍歷左邊
for(var k=0;k<j;k++){
//看落點是否為空且路上有無障礙
if(board[i][k]==0&&noBlockHorizontal(i,k,j,board)){
//move
showMoveAnimation(i,j,i,k);
//更新
board[i][k]=board[i][j];
board[i][j]=0;
continue;
}else if(board[i][k]==board[i][j]&&noBlockHorizontal(i,k,j,board)&&!hasConflicted[i][k]){
//move
showMoveAnimation(i,j,i,k);
//更新
board[i][k]+=board[i][j];
board[i][j]=0;
//分?jǐn)?shù)增加
score += board[i][k];
updateScore(score);
hasConflicted[i][k]=true;
continue;
}
}
}
}
}
//遍歷完后更新格子顯示狀態(tài),慢一點才能顯示動畫
setTimeout("updateBoardView()",200);
return true;
同理,也是只需要遍歷右邊的12個格子,先判斷遍歷到的這個格子是不是有值,有的話則遍歷其左邊的所有格子。這里就分成兩種情況
1.目標(biāo)格子是空的,且中間沒有阻礙,于是可以移動過去
2.目標(biāo)格子的值和自身是相等的,而且中間沒有阻礙,那么就可以合并
除了這兩種情況以外的都不需要做什么操作。
為此我們需要在support.js中寫一個檢測兩個格子間(同一行)有沒有阻礙的函數(shù)
noBlockHorizontal:
//檢測行上有無阻礙
function noBlockHorizontal(row,col1,col2,board){
for(var i=col1+1;i<col2;i++){
if(board[row][i]!=0)
return false;
}
return true;
}
這個我相信大家都看得懂,我就不解釋了。
對于第一種情況我們的操作是:
- 調(diào)用移動動畫函數(shù)
- 更新board數(shù)組,將自身的值傳給目標(biāo)格子,自身設(shè)為0
對于第二種情況我們的操作是:
- 調(diào)用移動動畫函數(shù)
- 更新board數(shù)組,目標(biāo)格子的值加上自身的值,自身設(shè)為0
- 移動動畫函數(shù)showMoveAnimation(fromx,fromy,tox,toy)
//移動動畫
function showMoveAnimation(fromx,fromy,tox,toy){
var numberCell=$("#number-cell-"+fromx+"-"+fromy);
numberCell.animate({
left:getPosLeft(tox,toy),
top:getPosTop(tox,toy)
},200);
}
我們是取自身這個數(shù)字方塊,給它加個animate。animate里面?zhèn)鞯氖悄繕?biāo)格子的left和top值,這個值是通過目標(biāo)格子的坐標(biāo)得到的。
- moveLeft()函數(shù)收尾
在一系列的修改都完成后,我們就需要根據(jù)現(xiàn)在的board來渲染格子視圖
所以最后添加,并返回true給鍵盤監(jiān)聽函數(shù)使用。
//遍歷完后更新格子顯示狀態(tài),慢一點才能顯示動畫
setTimeout("updateBoardView()",200);
return true;
- 最后的最后
其他方向的移動函數(shù)也是同理,我就不貼代碼了,幾乎一模一樣,細節(jié)上的一些數(shù)字不同罷了。當(dāng)一切都完成后,我們就已經(jīng)可以開始愉快的玩耍我們的游戲啦?。?/li>
