這是一個用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; }
<!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; }
看心情吧。