天天看點

h5遊戲:适應不同尺寸螢幕的WEB2048

一、界面展示及簡單介紹

先上完成後不同尺寸螢幕下的效果圖,界面模仿的原版2048:

h5遊戲:适應不同尺寸螢幕的WEB2048

                                                                                                       (768px<螢幕)

h5遊戲:适應不同尺寸螢幕的WEB2048

                                                                            (500px<螢幕<768px)

h5遊戲:适應不同尺寸螢幕的WEB2048

                                 (小于500px的超小螢幕)

原來預想左邊是遊戲清單,右邊是排行榜,暫時沒有做。

整體使用了bootstrap的栅格布局,左右兩列在xs尺寸下隐藏,中間列獨占12格。

在螢幕小于500px的時候額外設定樣式:

@media screen and (max-width: 500px){
   ...
}
           

動畫效果的實作學習了慕課網的2048課程,也算學習了一種新思路。

其它效果:

·手機端的滑動操作

·頁面放大縮小格子跟随移動

二、主要實作函數

這裡就隻貼出主要的代碼,盡量增加注釋,讓大家更好地了解實作邏輯。完整項目代碼可以在文章末尾的github位址中clone。

1.移動的邏輯,以向左移動為例

//判斷是否可以移動 board為4*4對應格子的數組
function canMoveLeft(){
    for (let i = 0; i<4; i++){
        for (let 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
}

function moveLeft() {
    if(!canMoveLeft())//判斷是否可以左移
        return;
    for(let x = 0; x<4; x++){
        //merged數組對應該行四個格子,判斷是否已經合并過,避免[2,2,2,2]合并為[8,0,0,0]之類情況
        var merged = [false,false,false,false];
        for(let y = 1; y<4; y++) {
            if (board[x][y] !=0){//目前行從左至右尋找有數字點
                var currentnum = board[x][y]; //目前移動點的數字
                var last = y; //目前點移動或尋找合并的過程中記錄目前位置
                for(var n = y-1; n>=0; n--){//從目前點左側相鄰格開始往左尋找空格或可合并格
                    if(board[x][n] == 0){
                        board[x][n] = currentnum;
                        board[x][last] = 0;
                        last = n;
                        continue;
                    }
                    else if(board[x][n] == currentnum && !merged[n]){
                        board[x][n] = currentnum * 2;
                        score+= currentnum * 2;
                        board[x][last] = 0;
                        last = n;
                        merged[n] = true;
                        continue;
                    }
                    else
                        break;//相鄰格不能移動和合并直接結束
                }
                moveAnimation(x,y,x,n+1,merged[n+1])//移動動畫
            }
        }
    }
    setTimeout("updateBoardView()",200) //移動完成後更新視圖
    setTimeout("ranNumber()",200)//等待移動動畫完成後再生成新數字
}
           

2.動畫效果的實作

實作思路為原本在html中寫的16個div格子(grid-cell)隻用來實作視覺效果,實際并沒有對這16個格子進行操作,而是在每次根據二維數組board記錄的資料生成16個position=absolute的div(number-cell),number-cell不顯示時大小都為0,位置都在對應實grid-cell的中心,在生成數字或移動時使用animate方法對number-cell進行操作,動畫結束後再更新視圖,代碼如下:

function updateBoardView() { //更新顯示
    $(".number-cell").remove();
    for (let i =0; i < 4; i++)
        for (let j = 0; j<4; j++){
            $(".grid-container").append('<div class="number-cell" id="number-cell-'+i+'-'+j+'"></div>');
            var theNumberCell = $('#number-cell-'+i+'-'+j);
            if(board[i][j] == 0){
                theNumberCell.css('width','0px');
                theNumberCell.css('height','0px');
                theNumberCell.css('top',getPosTop(i)+cellSize/2);
                theNumberCell.css('left',getPosLeft(j)+cellSize/2);
            }//cellSize為每個格子的長寬 cellSpace為每個格子之間的間距
            else {
                theNumberCell.css('width',cellSize);
                theNumberCell.css('height',cellSize);
                theNumberCell.css('top',getPosTop(i));
                theNumberCell.css('left',getPosLeft(j));
                theNumberCell.css('background-color',getCellColor(board[i][j]));
                theNumberCell.css('color',getNumColor(board[i][j]));
                theNumberCell.text(board[i][j]);
            }
        }
}
           

移動動畫代碼:

//傳入起始點坐标,終點坐标及是否是合并點
function moveAnimation(fromx,fromy,tox,toy,merged) { //移動動畫
    var numberCell = $('#number-cell-'+fromx+'-'+fromy);
    numberCell.animate({
        top:getPosTop(tox),//根據行數确定top距離
        left:getPosLeft(toy)//根據列數确定left距離
    },100)
    if (merged){ //合并動畫 脹大再還原的過程
        numberCell.animate({
            width:cellSize+cellSpace*2,
            height:cellSize+cellSpace*2,
            top:getPosTop(tox)-cellSpace,
            left:getPosLeft(toy)-cellSpace
        },50)
        numberCell.animate({
            width:cellSize,
            height:cellSize,
            top:getPosTop(tox),
            left:getPosLeft(toy)
        },50)
    }
}
           

三、總結

整個遊戲在整體的邏輯實作上會花費比較久的時間,另一個難點就是動畫的實作,幸好慕課網的教程給出了一種解決思路,總體來說2048還是一個比較簡單的項目。

項目完整代碼github位址:https://github.com/GaoMinjian/2048

項目線上體驗位址一:https://gaominjian.github.io/2048/index.html

項目線上體驗位址二:http://112.74.53.108/2048/

繼續閱讀