今年过完年来到学校步入了大三下学期,一番挣扎以后狠心放弃了学了一年多的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小游戏