今年過完年來到學校步入了大三下學期,一番掙扎以後狠心放棄了學了一年多的Java,決定開始轉戰喜歡的前端。而後天天泡在實驗室裏學習前端的基礎,一切從零開始,這期間恰好是各大互聯網公司春招的時候就順便往幾個大廠投了的簡歷,申請暑期實習。2048小遊戲是360奇舞學院的前端星的壓軸選拔題目。剛看到這個題目時一臉懵,由於我以前沒玩過2048小遊戲不知道這是個什麼東西【允悲】,接下來就跟你們一塊兒分享一下我用了5天的課餘時間從不知道這是個什麼遊戲到最後把它寫出來的過程吧。[這是一道30分的題目 我得了23分 大佬評語是動畫作的差了點]javascript
用JavaScript實現一個2048小遊戲css
題目要求:html
加分項前端
先一塊兒來看一下項目文件結構(此項目我沒用任何框架和jQuery庫)
頁面佈局樣式,先把頁面基本元素展現出來(HTML+CSS完整代碼)。
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no"/> <title>2048小遊戲</title> <link rel="stylesheet" type="text/css" href="./css/style.css"/> </head> <body> <header> <h1 class="game_title">2048小遊戲</h1> <a href="javascript:newGame();" id="newgame_btn">從新開始</a> </header> <main> <table id="checkerBoard"></table> <p class="number_title">得分:<span id="show_number"></span> 分</p> </main> <footer class="inner"> <p class="operation_pc">電腦:請用鍵盤方向鍵操做遊戲</p> <p class="operation_phone">手機:請滑動手機屏幕操做遊戲</p> </footer> <script type="application/javascript" src="./js/main.js"></script> <script type="application/javascript" src="./js/gameOver.js"></script> <script type="application/javascript" src="./js/move.js"></script> </body> </html>
這裏我作了手機端適配,這段代碼可讓頁面在手機端等比放大。java
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no"/>
body { background-color: #ced9c5; text-align: center; font-size: 20px; font-weight: bold; font-family: "Microsoft YaHei"; } /*header部分樣式*/ header{ display: block; margin: 0px auto; text-align: center; } header h1{ font-size: 1.5em; } header #newgame_btn{ width: 100px; padding:10px; background: #7da962; font-family:inherit; font-size: 20px; color: #fff; border-radius: 10px; text-decoration: none; } /*table樣式*/ table { margin: 0px auto; margin-top: 30px; border-radius: 10px; background-color: #bfc0bb; border-spacing: 8px; } td { width: 80px; height: 80px; border-radius: 10px; -webkit-transition: all 0.2s ease-out; -moz-transition: all 0.2s ease-out; -o-transition: all 0.2s ease-out; transition: all 0.2s ease-out; } /*footer部分樣式*/ main .number_title { font-size: 0.8em; } main #show_number{ color: #f8563d; font-size: 1.3em; } .inner { height: 50px; line-height: 1.8; text-align: center; padding: 15px; font-size: .7em; color: #656565; } footer .operation_pc{ border-top: 1px solid #bfc0bb; } footer .operation_phone{ border-bottom: 1px solid #bfc0bb; }
棋盤棋子初始化與產生新的棋子、計分和對產生的新棋子塗色
function GetRandom(Min,Max){ return Min + Math.round((Max-Min) * Math.random()); }
/*給隨機的格子放入隨機的2或4*/ function RandomNum(){ // 產生一個1~16的隨機數來獲取一個格子的ID let num = GetRandom(1,16); // 空格子數量計數器 let count = 0; // 判斷產生隨機格子內是否有數字 if(document.getElementById(num).innerHTML == ""){ // 產生2或4隨機數並放入隨機產生的空格子中 document.getElementById(num).innerHTML = GetRandom(1,2) * 2; } // 若是格子有數字遍歷棋盤是否放慢了棋子 else{ // 遍歷棋盤是否有空格子,若是有計數器就累加1 for(let i = 1; i <= 16; i++){ let piece_ = document.getElementById(i); if( piece_.innerHTML== ""){ count++; } } // 判斷棋盤是否有空格,若是有就再次執行隨機產生棋子的函數 if(count > 0){ RandomNum(); } } }
let color_object = { "":"#d3d3d3", "2":"#fef4f2", "4":"#fed9a2", "8":"#fc8c5e", "16":"#f8692f", "32":"#f8563d", "64":"#ff3936", "128":"#00c3dd", "256":"#00a4be", "512":"#00abcb", "1024":"#00abcb", "2048":"#00abcb", "4096":"#005d6e" };
function init(){ // 獲取棋盤table對象 let checkerBoard = document.getElementById("checkerBoard"); let text = ""; let id = 1; // 循環產生tr*4+td*4的行和列並給每個tablecell賦予ID值(用1~16分別表明每一個格子的ID值) for(let i = 1; i < 5; i++){ // 拼接<tr> text += "<tr>"; for(let j = i; j <= i+12; j += 4){ // 拼接<td id=""></td> text += "<td id=" + id + "></td>"; // 使td的ID值依次遞增 id++; } // 拼接</tr> text += "</tr>" } // 把循環產生的行和列放入table中 checkerBoard.innerHTML = text; // 在棋盤中循環放入兩個由RandomNum()產生的隨機位置和隨機的2或4 for(let k = 0; k < 2; k++){ RandomNum(); } Result(); }
/*新打開窗口時初始化遊戲*/ window.onload = init(); /*點擊從新開始遊戲按鈕時初始化遊戲*/ function newGame(){ init(); } /*生成一個介於兩個整數之間的隨機整數*/ function GetRandom(Min,Max){ return Min + Math.round((Max-Min) * Math.random()); } /*給隨機的格子放入隨機的2或4*/ function RandomNum(){ // 產生一個1~16的隨機數來獲取一個格子的ID let num = GetRandom(1,16); // 空格子數量計數器 let count = 0; // 判斷產生隨機格子內是否有數字 if(document.getElementById(num).innerHTML == ""){ // 產生2或4隨機數並放入隨機產生的空格子中 document.getElementById(num).innerHTML = GetRandom(1,2) * 2; } // 若是格子有數字遍歷棋盤是否放慢了棋子 else{ // 遍歷棋盤是否有空格子,若是有計數器就累加1 for(let i = 1; i <= 16; i++){ let piece_ = document.getElementById(i); if( piece_.innerHTML== ""){ count++; } } // 判斷棋盤是否有空格,若是有就再次執行隨機產生棋子的函數 if(count > 0){ RandomNum(); } } } /*初始化遊戲數據*/ function init(){ // 獲取棋盤table對象 let checkerBoard = document.getElementById("checkerBoard"); let text = ""; let id = 1; // 循環產生tr*4+td*4的行和列並給每個tablecell賦予ID值(用1~16分別表明每一個格子的ID值) for(let i = 1; i < 5; i++){ // 拼接<tr> text += "<tr>"; for(let j = i; j <= i+12; j += 4){ // 拼接<td id=""></td> text += "<td id=" + id + "></td>"; // 使td的ID值依次遞增 id++; } // 拼接</tr> text += "</tr>" } // 把循環產生的行和列放入table中 checkerBoard.innerHTML = text; // 在棋盤中循環放入兩個由RandomNum()產生的隨機位置和隨機的2或4 for(let k = 0; k < 2; k++){ RandomNum(); } Result(); } /*給不一樣數值的棋子塗上不一樣的顏色,並計算得分*/ function Result(){ // 給分數初始值爲0 let score = 0; // 計數棋子的數量 let count = 0; // 定義一個數值對應顏色的對象 let color_object = { "":"#d3d3d3", "2":"#fef4f2", "4":"#fed9a2", "8":"#fc8c5e", "16":"#f8692f", "32":"#f8563d", "64":"#ff3936", "128":"#00c3dd", "256":"#00a4be", "512":"#00abcb", "1024":"#00abcb", "2048":"#00abcb", "4096":"#005d6e" }; for(let i = 1; i <= 16; i++){ // 遍歷全部棋子,給對應數值的棋子塗上對應的顏色 let text = document.getElementById(i); text.style.backgroundColor = color_object[text.innerHTML]; // 以棋子數值爲8的棋子做爲臨界給數值大於等於8和小於8的棋子數字分別設置不一樣的顏色 if(text.innerHTML >= 8){ text.style.color = "#fff"; }else{ text.style.color = "#6e6f71"; } // 若是格子的數值不爲空就把此格子上棋子的數值累加做爲當前得分 if(text.innerHTML != ""){ score += parseInt(text.innerHTML); count++; } } // 若是棋子數量爲2時,即遊戲剛初始化,此時分數置零 if(count == 2){ document.getElementById("show_number").innerHTML = 0; } // 若是棋子數量不是二則正常累加得分 else{ document.getElementById("show_number").innerHTML = score; } }
接下來開始讓棋子動起來(pc端用方向鍵操做,移動端用手指滑動操做)
function Change(piece_1,piece_2){ // 判斷若是棋子要移動的方向有空格就將其移動 if(piece_1.innerHTML == "" && piece_2.innerHTML != ""){ res = true; piece_1.innerHTML = piece_2.innerHTML; piece_2.innerHTML = ""; } // 判斷若是相鄰棋子都不爲空而且數值相等就將他們合併,同時將一個格子置空 else if(piece_1.innerHTML != "" && piece_1.innerHTML == piece_2.innerHTML){ res = true; piece_1.innerHTML = parseInt(piece_1.innerHTML) + parseInt(piece_2.innerHTML); piece_2.innerHTML = ""; } }
document.onkeydown = function pc_move(){ res = false; if(event.keyCode == 38) Top(); else if(event.keyCode == 40) Down(); else if(event.keyCode == 37) Left(); else if(event.keyCode == 39) Right(); // 判斷遊戲是否結束 gameOver(); // 若是棋子移動了獲得的res==true,就再次產生新的棋子 if(res) RandomNum(); // 調用Result()函數,給棋子塗色並記錄當前分數 Result(); }
e.preventDefault();
function touch_move(){ // 定義滑動的起點和終點X、Y座標值 let startX = 0; let startY = 0; let endX = 0; let endY = 0; // 獲取棋盤對象 let table = document.getElementById("checkerBoard"); // 給棋盤綁定'touchstart'事件 table.addEventListener('touchstart',function(e){ let touch = event.targetTouches[0]; // 在手指點擊屏幕時阻止屏幕拖動事件 e.preventDefault(); //獲取手指滑動起點座標 startX = touch.pageX; startY = touch.pageY; }); // 給棋盤綁定'touchmove'事件 table.addEventListener('touchmove',function(e){ let touch = event.targetTouches[0]; // 在手指滑動屏幕時阻止屏幕拖動事件 e.preventDefault(); //獲取手指滑動屏幕的終點座標 endX = touch.pageX; endY = touch.pageY; }); // 給棋盤綁定'touchend'事件 table.addEventListener('touchend',function(e){ // 在手指滑動屏幕結束時阻止屏幕拖動事件 e.preventDefault(); //滑動結束,計算出手指分別在X、Y軸上滑動距離 let distanceX = endX - startX; let distanceY = endY - startY; res = false; // console.log("startX " + startX + " startY" + startY); // console.log("endX" + endX + " endY" + endY); // console.log("distanceX" + distanceX + " distanceY" + distanceY) // console.log("------------------------------------------------------------------------------"); // 若是終點座標X、Y值都不爲零則進入下一步判斷滑動方向 if(endX!=0 && endY!=0){ //向上滑動 if(Math.abs(distanceY) > Math.abs(distanceX) && distanceY < -10){ Top(); } //向下滑動 else if(Math.abs(distanceY) > Math.abs(distanceX) && distanceY > 10){ Down(); } //向左滑動 else if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX < -10){ Left(); } //向右滑動 else if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX > 10){ Right(); } // 判斷遊戲是否結束 gameOver(); // 若是棋子移動了獲得的res==true,就再次產生新的棋子 if(res){ RandomNum(); } // 將以上綁定事件獲取的起始點座標值置零 startX = startY = endX = endY = 0; } // 調用Result()函數,給棋子塗色並記錄當前分數 Result(); }); } touch_move();
// 控制棋盤是否產生隨機的棋子,當res==true時產生新的棋子 let res = false; /*移動棋子使相鄰而且相同數值的棋子合併,同時將數值相加*/ function Change(piece_1,piece_2){ // 判斷若是棋子要移動的方向有空格就將其移動 if(piece_1.innerHTML == "" && piece_2.innerHTML != ""){ res = true; piece_1.innerHTML = piece_2.innerHTML; piece_2.innerHTML = ""; } // 判斷若是相鄰棋子都不爲空而且數值相等就將他們合併,同時將一個格子置空 else if(piece_1.innerHTML != "" && piece_1.innerHTML == piece_2.innerHTML){ res = true; piece_1.innerHTML = parseInt(piece_1.innerHTML) + parseInt(piece_2.innerHTML); piece_2.innerHTML = ""; } } /*向上移動棋子*/ function Top(){ for(let i = 1; i < 5; i++){ for(let j = i; j <= i + 12; j += 4){ for(let k = j; k > 4; k -= 4){ let piece_1 = document.getElementById(k - 4); let piece_2 = document.getElementById(k); Change(piece_1,piece_2); } } } } /*向下移動棋子*/ function Down(){ for(let i = 1; i < 5; i++){ for(let j = i + 12; j >= i; j -= 4){ for(let k = j; k < 13; k += 4){ let piece_1 = document.getElementById(k + 4); let piece_2 = document.getElementById(k); Change(piece_1,piece_2); } } } } /*向左移動棋子*/ function Left(){ for(let i = 1; i <= 13; i += 4){ for(let j = i; j <= i + 3; j += 1){ for(let k = j; k > i; k -= 1){ let piece_1 = document.getElementById(k - 1); let piece_2 = document.getElementById(k); Change(piece_1,piece_2); } } } } /*向右移動棋子*/ function Right(){ for(let i = 1; i <= 13; i += 4){ for(let j = i + 4; j >= i; j -= 1){ for(let k = j; k < i + 3; k += 1){ let piece_1 = document.getElementById(k + 1); let piece_2 = document.getElementById(k); Change(piece_1,piece_2); } } } } /*按壓鍵盤方向鍵使棋子移動*/ document.onkeydown = function pc_move(){ res = false; if(event.keyCode == 38) Top(); else if(event.keyCode == 40) Down(); else if(event.keyCode == 37) Left(); else if(event.keyCode == 39) Right(); // 判斷遊戲是否結束 gameOver(); // 若是棋子移動了獲得的res==true,就再次產生新的棋子 if(res) RandomNum(); // 調用Result()函數,給棋子塗色並記錄當前分數 Result(); } /*滑動手機屏幕使棋子移動*/ function touch_move(){ // 定義滑動的起點和終點X、Y座標值 let startX = 0; let startY = 0; let endX = 0; let endY = 0; // 獲取棋盤對象 let table = document.getElementById("checkerBoard"); // 給棋盤綁定'touchstart'事件 table.addEventListener('touchstart',function(e){ let touch = event.targetTouches[0]; // 在手指點擊屏幕時阻止屏幕拖動事件 e.preventDefault(); //獲取手指滑動起點座標 startX = touch.pageX; startY = touch.pageY; }); // 給棋盤綁定'touchmove'事件 table.addEventListener('touchmove',function(e){ let touch = event.targetTouches[0]; // 在手指滑動屏幕時阻止屏幕拖動事件 e.preventDefault(); //獲取手指滑動屏幕的終點座標 endX = touch.pageX; endY = touch.pageY; }); // 給棋盤綁定'touchend'事件 table.addEventListener('touchend',function(e){ // 在手指滑動屏幕結束時阻止屏幕拖動事件 e.preventDefault(); //滑動結束,計算出手指分別在X、Y軸上滑動距離 let distanceX = endX - startX; let distanceY = endY - startY; res = false; // console.log("startX " + startX + " startY" + startY); // console.log("endX" + endX + " endY" + endY); // console.log("distanceX" + distanceX + " distanceY" + distanceY) // console.log("------------------------------------------------------------------------------"); // 若是終點座標X、Y值都不爲零則進入下一步判斷滑動方向 if(endX!=0 && endY!=0){ //向上滑動 if(Math.abs(distanceY) > Math.abs(distanceX) && distanceY < -10){ Top(); } //向下滑動 else if(Math.abs(distanceY) > Math.abs(distanceX) && distanceY > 10){ Down(); } //向左滑動 else if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX < -10){ Left(); } //向右滑動 else if(Math.abs(distanceX) > Math.abs(distanceY) && distanceX > 10){ Right(); } // 判斷遊戲是否結束 gameOver(); // 若是棋子移動了獲得的res==true,就再次產生新的棋子 if(res){ RandomNum(); } // 將以上綁定事件獲取的起始點座標值置零 startX = startY = endX = endY = 0; } // 調用Result()函數,給棋子塗色並記錄當前分數 Result(); }); } touch_move();
進行遊戲結束判斷(遍歷棋盤當棋盤放滿棋子,而且每一個棋子上下左右相鄰位置都不相同則遊戲結束)
/*遊戲結束判斷*/ function gameOver(){ // 設置一個空格子計數器 let count = 0; // 遍歷棋盤是否有空格子,若是有計數器就累加1 for(let i = 1; i <= 16; i++){ let piece_ = document.getElementById(i); if( piece_.innerHTML== ""){ count++; } } // 判斷棋盤是否擺滿棋子 if(count == 0){ // 當棋盤擺滿棋子時,遍歷全部棋子看其與相鄰的棋子數值是否相等,一旦有相等的計數器就累加1 for(let i = 1; i <= 16; i++){ let piece_self = document.getElementById(i); let piece_add_1 = document.getElementById(i + 1); let piece_cut_1 = document.getElementById(i - 1); let piece_add_4 = document.getElementById(i + 4); let piece_cut_4 = document.getElementById(i - 4); switch (i){ case 1: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML)){ count++; } break; case 2: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML)){ count++; } break; case 3: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML)){ count++; } break; case 4: if(parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML)){ count++; } break; case 5: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 6: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 7: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 8: if(parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 9: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 10: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 11: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 12: if(parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_add_4.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 13: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 14: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 15: if(parseInt(piece_self.innerHTML) == parseInt(piece_add_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; case 16: if(parseInt(piece_self.innerHTML) == parseInt(piece_cut_1.innerHTML) || parseInt(piece_self.innerHTML) == parseInt(piece_cut_4.innerHTML)){ count++; } break; default: break; } } // 當遍歷全部棋子後與相鄰位置棋子數值都不相等,遊戲結束 if(count == 0){ // 獲取當前得分 let score = document.getElementById("show_number").innerHTML; alert("瀟灑人生,極限挑戰。遊戲結束! 您的得分:"+score+" 分"); // 點擊肯定按鈕後初始化遊戲 init(); } } }
至此整個項目設計過程就結束了,因爲剛轉入前端代碼書寫確定不是很優雅,歡迎你們對個人代碼不足之處進行指正。git
(寢室已經斷電,室友已經是鼾聲四起,準備睡覺啦,明天一早還要起來去上課【允悲】)github
完整項目訪問 個人github倉庫
點擊此處 體驗個人2048小遊戲