2048小遊戲——網頁版(基礎篇)

這是一個用js寫的網頁版2048遊戲,實現2048遊戲的基本功能。javascript


好比:繪製網格、隨機生成數字、動畫移動數字、累計分數、重置遊戲等。css


同時,筆者在本身的理解下,對代碼進行了很是詳細的註釋,相信有一點點基礎的開發人員都能迅速看懂,快來試試吧!html


固然,大神還能夠在這個文檔的基礎上對遊戲進行改進,好比添加一些更炫酷的動畫效果,自定義數字、文字、圖像等。
java


該項目的全部代碼已上傳,歡迎下載:點擊打開連接jquery


固然你也能夠查看本文接下來給你展現的部分代碼。數組


該項目主要由如下幾個部分組成:app


2048.css :是關於字體、表格、排版樣式的定義文檔。包括字體、表格、數字的大小、顏色、邊距等。dom

index.html :是該網頁的主界面設計文檔。包括設置標題文字、分數、棋盤格,以及導入會用到的css文件、js文件。函數

main2048.js :是該遊戲的主要功能的實現文檔。包括開始遊戲、初始化數據、隨機生成數字、鍵盤上下左右的響應、數字移動的變化、遊戲結束。字體

showAnimation.js :是該遊戲的動畫顯示的實現文檔。包括數字顯示的動畫、數字移動的動畫、分數刷新顯示。

support2048.js :是該遊戲的一些小細節處理的實現文檔。能夠理解爲對 main2048.js 中經常使用函數的封裝,方便屢次調用此類函數。包括獲取單元格的座標、設置數字的顏色、判斷格子是否爲空、判斷數字可否移動等。

----------------------------------------------------------------------------------    具體代碼實現以下    -------------------------------------------------------------------------------------------------------------------

2048.css

header {
    display: block;
    margin: 0 auto;
    width: 500px;
    text-align: center;
}

header h1 {
    font-family: Arial;
    font-size: 60px;
    font-weight: bold;
}

header #newgamebutton {
    display: block;
    margin: 20px auto;

    width: 100px;
    padding: 10px 10px;
    background-color: #8f7a66;

    font-family: Arial;
    color: white;

    border-radius: 10px;

    text-decoration: none;
}

header #newgamebutton:hover {
    background-color: #9f8b77;
}

header p {
    font-family: Arial;
    font-size: 25px;
    margin: 20px auto;
}

#grid-container {
    width: 460px;
    height: 460px;
    padding: 20px;

    margin: 50px auto;
    background-color: #bbada0;

    border-radius: 10px;
    position: relative;
}

.grid-cell {
    width: 100px;
    height: 100px;
    border-radius: 6px;
    background-color: #ccc0b3;

    position: absolute;
}

.number-cell {
    border-radius: 6px;

    font-family: Arial;
    font-weight: bold;
    font-size: 60px;
    line-height: 100px;
    text-align: center;

    position: absolute;
}


index.html 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">

    <title>2048</title>
    <link rel="stylesheet" type="text/css" href="2048.css"/>

    <script type="text/javascript" src="http://libs.baidu.com/jquery/1.9.0/jquery.min.js"></script>
    <script type="text/javascript" src="support2048.js"></script>
    <script type="text/javascript" src="showAnimation.js"></script>
    <script type="text/javascript" src="main2048.js"></script>

</head>
<body>

<!-- 繪製標題 -->
<header>
    <h1>2048</h1>
    <a href="javascript:newgame();" id="newgamebutton">New Game</a>
    <p>score:<span id="score">0</span></p>
</header>

<!-- 繪製棋盤格 -->
<div id="grid-container">
    <div class="grid-cell" id="grid-cell-0-0"></div>
    <div class="grid-cell" id="grid-cell-0-1"></div>
    <div class="grid-cell" id="grid-cell-0-2"></div>
    <div class="grid-cell" id="grid-cell-0-3"></div>

    <div class="grid-cell" id="grid-cell-1-0"></div>
    <div class="grid-cell" id="grid-cell-1-1"></div>
    <div class="grid-cell" id="grid-cell-1-2"></div>
    <div class="grid-cell" id="grid-cell-1-3"></div>

    <div class="grid-cell" id="grid-cell-2-0"></div>
    <div class="grid-cell" id="grid-cell-2-1"></div>
    <div class="grid-cell" id="grid-cell-2-2"></div>
    <div class="grid-cell" id="grid-cell-2-3"></div>

    <div class="grid-cell" id="grid-cell-3-0"></div>
    <div class="grid-cell" id="grid-cell-3-1"></div>
    <div class="grid-cell" id="grid-cell-3-2"></div>
    <div class="grid-cell" id="grid-cell-3-3"></div>
</div>
</body>
</html>

main2048.js

/**
 * Created by Kay on 2016/3/7.
 */

// --------------------------------------------------------------------------------------------------------------------
var board = new Array();
var score = 0;
var hasConflicted = new Array();// 用來判斷每一個格子是否已經發生過碰撞,從而避免一會兒加好幾個格子

$(document).ready(function () {
    newgame();
});

function newgame() {

    // 初始化棋盤格
    init();

    // 在隨機兩個格子生成數字
    generateOneNumber();
    generateOneNumber();
}

// --------------------------------------------------------------------------------------------------------------------
/*
 *  一、初始化棋盤格 gridCell
 *  二、初始化二維數組 用於存儲數據 board
 *  三、初始化數據 清零 updateBoardView();
 */
function init() {
    for (var i = 0; i < 4; i++)
        for (var j = 0; j < 4; j++) {
            var gridCell = $("#grid-cell-" + i + "-" + j);
            gridCell.css('top', getPosition(i));
            gridCell.css('left', getPosition(j));
        }

    for (var i = 0; i < 4; i++) {
        board[i] = new Array();
        hasConflicted[i] = new Array();
        for (var j = 0; j < 4; j++) {
            board[i][j] = 0;
            hasConflicted[i][j] = false;
        }
    }

    updateBoardView();

    score = 0;

    updateScore(score);

}

// --------------------------------------------------------------------------------------------------------------------
// 初始化數據,就是將數據可視化!根據board[i][j]存的數值來畫圖!
function updateBoardView() {
    $(".number-cell").remove();
    for (var i = 0; i < 4; i++)
        for (var 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", getPosition(i) + 50);
                theNumberCell.css("left", getPosition(j) + 50);
            } else {
                theNumberCell.css('width', '100px');
                theNumberCell.css('height', '100px');
                theNumberCell.css('top', getPosition(i));
                theNumberCell.css('left', getPosition(j));
                theNumberCell.css('background-color', getNumberBackgroundColor(board[i][j]));
                theNumberCell.css('color', getNumberColor(board[i][j]));
                theNumberCell.text(board[i][j]);
            }
            hasConflicted[i][j] = false;
        }
}

// --------------------------------------------------------------------------------------------------------------------
// 隨機選一個格子生成一個數字
function generateOneNumber() {

    if (nospace(board))
        return false;

    // 隨機一個位置
    var randx = parseInt(Math.floor(Math.random() * 4));
    var randy = parseInt(Math.floor(Math.random() * 4));

    // 設置一個時間參數,50次之內系統還未生成一個空位置,那麼就進行人工找一個空位置
    var times = 0;
    while (times < 50) {
        if (board[randx][randy] == 0)
            break;

        randx = parseInt(Math.floor(Math.random() * 4));
        randy = parseInt(Math.floor(Math.random() * 4));

        times++;
    }
    if (times == 50) {
        for (var i = 0; i < 4; i++)
            for (var j = 0; j < 4; j++) {
                if (board[i][j] == 0) {
                    randx = i;
                    randy = j;
                }
            }
    }

    // 隨機一個數字
    var randNumber = Math.random() < 0.5 ? 2 : 4;

    // 在隨機位置顯示隨機數字
    board[randx][randy] = randNumber;
    showNumberWithAnimation(randx, randy, randNumber);

    return true;
}

// --------------------------------------------------------------------------------------------------------------------
// 判斷鍵盤的響應時間 上下左右
$(document).keydown(function (event) {
    event.preventDefault();
    switch (event.keyCode) {
        case 37: // left 向左移動
            if (moveLeft()) {
                setTimeout("generateOneNumber()", 210);
                setTimeout("isgameover()", 300);
            }
            ;
            break;
        case 38: // up 向上移動
            if (moveUp()) {
                setTimeout("generateOneNumber()", 210);
                setTimeout("isgameover()", 300);
            }
            ;
            break;
        case 39: // right 向右移動
            if (moveRight()) {
                setTimeout("generateOneNumber()", 210);
                setTimeout("isgameover()", 300);
            }
            ;
            break;
        case 40: // down 向下移動
            if (moveDown()) {
                setTimeout("generateOneNumber()", 210);
                setTimeout("isgameover()", 300);
            }
            ;
            break;
        default: // default
            break;
    }
});

// --------------------------------------------------------------------------------------------------------------------
// 向左移動
function moveLeft() {

    // 一、首先,判斷可否向左移動
    if (!canMoveLeft(board))
        return false;

    /*二、若是能夠向左移動:
     *   ①當前的數字是否爲0,不爲0則進行左移 board[i][j] != 0
     *   ②若是左側爲空格子,則數字進行一個移位操做 board[i][k] == 0
     *   ③若是左側有數字且不相等,則數字仍是進行移位操做 noBlockHorizontal
     *   ④若是左側有數字且相等,則數字進行相加操做 board[i][k] == board[i][j]
     */
    for (var i = 0; i < 4; i++)
        for (var j = 1; j < 4; j++) {
            if (board[i][j] != 0) {
                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);
                        //add
                        board[i][k] += board[i][j];
                        board[i][j] = 0;
                        //add score
                        score += board[i][k];
                        updateScore(score);

                        hasConflicted[i][k] = true;
                        continue;
                    }
                }
            }
        }
    // 三、初始化數據 updateBoardView()
    // 爲顯示動畫效果,設置該函數的等待時間200毫秒
    setTimeout("updateBoardView()", 200);
    return true;
}

// --------------------------------------------------------------------------------------------------------------------
// 向上移動
function moveUp() {

    if (!canMoveUp(board))
        return false;

    //moveUp
    for (var j = 0; j < 4; j++)
        for (var i = 1; i < 4; i++) {
            if (board[i][j] != 0) {
                for (var k = 0; k < i; k++) {
                    if (board[k][j] == 0 && noBlockVertical(j, k, i, board)) {
                        //move
                        showMoveAnimation(i, j, k, j);
                        board[k][j] = board[i][j];
                        board[i][j] = 0;
                        continue;
                    }
                    else if (board[k][j] == board[i][j] && noBlockVertical(j, k, i, board) && !hasConflicted[k][j]) {
                        //move
                        showMoveAnimation(i, j, k, j);
                        //add
                        board[k][j] += board[i][j];
                        board[i][j] = 0;
                        //add score
                        score += board[k][j];
                        updateScore(score);

                        hasConflicted[k][j] = true;
                        continue;
                    }
                }
            }
        }
    setTimeout("updateBoardView()", 200);
    return true;
}

// --------------------------------------------------------------------------------------------------------------------
// 向右移動
function moveRight() {
    if (!canMoveRight(board))
        return false;

    //moveRight
    for (var i = 0; i < 4; i++)
        for (var j = 2; j >= 0; j--) {
            if (board[i][j] != 0) {
                for (var k = 3; k > j; k--) {
                    if (board[i][k] == 0 && noBlockHorizontal(i, j, k, 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, j, k, board) && !hasConflicted[i][k]) {
                        //move
                        showMoveAnimation(i, j, i, k);
                        //add
                        board[i][k] += board[i][j];
                        board[i][j] = 0;
                        //add score
                        score += board[i][k];
                        updateScore(score);

                        hasConflicted[i][k] = true;
                        continue;
                    }
                }
            }
        }
    setTimeout("updateBoardView()", 200);
    return true;
}

// --------------------------------------------------------------------------------------------------------------------
// 向下移動
function moveDown() {
    if (!canMoveDown(board))
        return false;

    //moveDown
    for (var j = 0; j < 4; j++)
        for (var i = 2; i >= 0; i--) {
            if (board[i][j] != 0) {
                for (var k = 3; k > i; k--) {
                    if (board[k][j] == 0 && noBlockVertical(j, i, k, board)) {
                        //move
                        showMoveAnimation(i, j, k, j);
                        board[k][j] = board[i][j];
                        board[i][j] = 0;
                        continue;
                    }
                    else if (board[k][j] == board[i][j] && noBlockVertical(j, i, k, board) && !hasConflicted[k][j]) {
                        //move
                        showMoveAnimation(i, j, k, j);
                        //add
                        board[k][j] += board[i][j];
                        board[i][j] = 0;
                        //add score
                        score += board[k][j];
                        updateScore(score);

                        hasConflicted[k][j] = true;
                        continue;
                    }
                }
            }
        }
    setTimeout("updateBoardView()", 200);
    return true;
}

// --------------------------------------------------------------------------------------------------------------------
// 遊戲結束
function isgameover() {
    if (nospace(board) && nomove(board)) {
        gameover();
    }
}

function gameover() {
    alert("遊戲結束!您的得分爲:" + score);
}<strong>

</strong>


showAnimation.js

/**
 * Created by Kay on 2016/3/7.
 */

// --------------------------------------------------------------------------------------------------------------------
/* 顯示數字的動畫:
 * 在 x=i,y=j 的位置上 顯示數字 該數字的值 = randNumber
 * 在這個顯示過程當中 設置了一個50毫秒的動畫效果
 */
function showNumberWithAnimation(i, j, randNumber) {
    var numberCell = $('#number-cell-' + i + "-" + j);

    numberCell.css('background-color', getNumberBackgroundColor(randNumber));
    numberCell.css('color', getNumberColor(randNumber));
    numberCell.text(randNumber);

    numberCell.animate({
        width: "100px",
        height: "100px",
        top: getPosition(i),
        left: getPosition(j)
    }, 50);
}

// --------------------------------------------------------------------------------------------------------------------
/* 移動數字的動畫:
 * 從 x=fromx,y=fromy 的位置 移動到  x=tox,y=toy 的位置
 * 在這個顯示過程當中 設置了一個200毫秒的動畫效果
 */
function  showMoveAnimation(fromx, fromy, tox, toy){
    var numberCell = $('#number-cell-' + fromx + '-' +fromy );
    numberCell.animate({
        top:getPosition( tox ),
        left:getPosition( toy )
    },200);
}

// --------------------------------------------------------------------------------------------------------------------
// 分數刷新顯示,此處未設置動畫
function  updateScore(score){
    $('#score').text(score);
}


support2048.js

/**
 * Created by Kay on 2016/3/7.
 */

// --------------------------------------------------------------------------------------------------------------------
// 獲取每一個單元格的座標
function getPosition( pos ) {
    return 20 + pos * 120;
}

// --------------------------------------------------------------------------------------------------------------------
// 設置不一樣數字的不一樣背景顏色
function getNumberBackgroundColor(number) {
    switch (number) {
        case 2:
            return "#eee4da";
            break;
        case 4:
            return "#ede0c8";
            break;
        case 8:
            return "#f2b179";
            break;
        case 16:
            return "#f59563";
            break;
        case 32:
            return "#f67c5f";
            break;
        case 64:
            return "#f65e3b";
            break;
        case 128:
            return "#edcf72";
            break;
        case 256:
            return "#edcc61";
            break;
        case 512:
            return "#9c0";
            break;
        case 1024:
            return "#33b5e5";
            break;
        case 2048:
            return "#09c";
            break;
        case 4096:
            return "#a6c";
            break;
        case 3192:
            return "#93c";
            break;
    }
    return "black";
}

// --------------------------------------------------------------------------------------------------------------------
// 設置數字的顏色:2和4的顏色都爲#776e65,其它數字的顏色爲白色
function getNumberColor(number) {
    if ( number <= 4 )
        return "#776e65";

    return "white";
}

// --------------------------------------------------------------------------------------------------------------------
// 判斷當前格子是否有數字 即判斷是否是一個「非空(nospace)」的格子
function nospace(board) {
    for ( var i = 0; i < 4; i++ )
        for ( var j = 0; j < 4; j++ )
            if ( board[i][j] == 0 ) // 若是沒有數字,返回false
                return false;
    // 若是有數字,返回true
    return true;
}

// --------------------------------------------------------------------------------------------------------------------
/* 判斷可否向左移動
 * 一、只須要判斷每一行的後3列格子便可。
 * 二、能夠移動的條件是:
 *   ①當前格子有數字,即 board[i][j] != 0
 *   ②左側格子沒有數字,即 (board[i][j - 1] == 0
 *   ③左側格子和當前格子數字相同,即 board[i][j - 1] == board[i][j]
 */
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;
}

// --------------------------------------------------------------------------------------------------------------------
// 判斷可否向上、右、下移動
function canMoveUp(board) {
    for (var j = 0; j < 4; j++)
        for (var i = 1; i < 4; i++)
            if (board[i][j] != 0)
                if (board[i - 1][j] == 0 || board[i - 1][j] == board[i][j])
                    return true;
    return false;
}
function canMoveRight(board) {
    for (var i = 0; i < 4; i++)
        for (var j = 0; j < 3; j++)
            if (board[i][j] != 0)
                if (board[i][j+1] == 0 || board[i][j+1] == board[i][j])
                    return true;
    return false;
}
function canMoveDown(board) {
    for (var j = 0; j < 4; j++)
        for (var i = 0; i < 3; i++)
            if (board[i][j] != 0)
                if (board[i + 1][j] == 0 || board[i + 1][j] == board[i][j])
                    return true;
    return false;
}

// --------------------------------------------------------------------------------------------------------------------
// 判斷水平方向是否可移動,即水平方向的兩個目標格子之間沒有其餘數字 noBlockHorizontal
function noBlockHorizontal(row, col1, col2, board) {
    for (var i = col1 + 1; i < col2; i++)
        if (board[row][i] != 0) // 若是在這二者之間的其它格子有數字,返回false
            return false;
    // 若是二者之間沒數字,返回true
    return true;
}

// --------------------------------------------------------------------------------------------------------------------
// 判斷垂直方向是否可移動,即垂直方向的兩個目標格子之間沒有其餘數字 noBlockHorizontal
function noBlockVertical(col, row1, row2, board) {
    for (var i = row1 + 1; i < row2; i++)
        if (board[i][col] != 0) // 若是在這二者之間的其它格子有數字,返回false
            return false;
    // 若是二者之間沒數字,返回true
    return true;
}

function nomove( board ){
    if( canMoveLeft( board ) ||
        canMoveRight( board ) ||
        canMoveUp( board ) ||
        canMoveDown( board ) )
        return false;

    return true;
}

接下來,可能會再出個 「2048小遊戲——網頁版( 提升篇)」。主要是想對該遊戲進行一個改進,2048的數字換成圖片、支持手機端的滑動操做等。

看心情吧。

相關文章
相關標籤/搜索