jQuery编写网页版2048小游戏

大致介绍

看了一个实现网页版2048小游戏的视频,觉得能做出自己以前喜欢玩的小游戏很有意思便自己动手试了试,真正的验证了这句话-不要以为你以为的就是你以为的,看视频时觉得看懂了,会写了,但是自己实现起来会遇到各种问题。比如,在最后判断游戏是否结束的时候,我写的语句语法是对的,但就是不执行。最后通过对视频源码的分析对比,发现原作者写的一个setTimeout定时器有额外的意思,本来我以为它就是简单的一个延时动画,其实他是在等待另外一个函数执行完毕。-_-||。最后还是很高兴能写出来,也改进了一些源代码的不足。

这篇博客并不是详细的讲解,只是大致介绍函数的作用,其中实现的细节注释中有解释,网上的这个源码有点乱,如果想看比较整齐的源码或者视频的可以QQ联系我(免费)(找共同学习的伙伴)

思路

这个小游戏可以抽象化分为3层(我觉得这样能更好理解)

◆最底下的一层是基本的样式(可见的)

◆中间的层是最主要的,是一个4x4的二维数组,游戏中我们都是对这个二维数组进行操作(不可见的)

◆最上面的一层也是一个4x4的二维数组,它只是根据第二层数组的每个数显示样式(可见的)

我们通过最底下的一层显示最基本的16个小方格,通过键盘的按键或者手指在屏幕的滑动来操作中间层的数组,最后在通过最上面的一层显示出数字

基本结构与样式

基本的结构和样式都挺简单,直接看代码

结构:

<div id="test2048">
 <div id="header">
  <h1>2048</h1>
  <a href="javascript:newgame()" >开始新的游戏</a>
  <p>分数:<span id="score">0</span></p>
 </div>
 <div id="container">
  <div class="cell" id="cell-0-0"></div>
  <div class="cell" id="cell-0-1"></div>
  <div class="cell" id="cell-0-2"></div>
  <div class="cell" id="cell-0-3"></div>
  <div class="cell" id="cell-1-0"></div>
  <div class="cell" id="cell-1-1"></div>
  <div class="cell" id="cell-1-2"></div>
  <div class="cell" id="cell-1-3"></div>
  <div class="cell" id="cell-2-0"></div>
  <div class="cell" id="cell-2-1"></div>
  <div class="cell" id="cell-2-2"></div>
  <div class="cell" id="cell-2-3"></div>
  <div class="cell" id="cell-3-0"></div>
  <div class="cell" id="cell-3-1"></div>
  <div class="cell" id="cell-3-2"></div>
  <div class="cell" id="cell-3-3"></div>
 </div>
 </div>

样式:

*{
 margin: 0;
 padding: 0;
}
#test2048{
 font-family: Arial;
 margin: 0 auto;
 text-align: center;
}
#header{
 margin: 20px;
}
#header a{
 font-family: Arial;
 text-decoration: none;
 display: block;
 color: white;
 margin: 20px auto;
 width: 125px;
 height: 35px;
 text-align: center;
 line-height: 40px;
 background-color: #8f7a66;
 border-radius: 10px;
 font-size: 15px;
}
#header p{
 font-family: Arial;
 font-size: 20px;
}
#container{
 width: 460px;
 height: 460px;
 background-color: #bbada0;
 margin: 0 auto;
 border-radius: 10px;
 position: relative;
 padding: 20px;
}
.cell{
 width: 100px;
 height: 100px;
 border-radius: 6px;
 background-color: #ccc0b3;
 position: absolute;
}

从CSS样式可以看出,我们并没有对每个格子的位置进行设置,因为如果用CSS给每个格子设置样式代码量太大,而且他们的位置有一定的规律,所以我们可以用js循环来完成每个格子样式的设置

代码:

// 初始化棋盘格
function initialize(){
 for(var i=0;i<4;i++){
  for(var j=0;j<4;j++){
   // 设置棋盘格的位置
   var everyCell = $('#cell-'+ i +'-'+ j);
   everyCell.css({top:getPos(i),left:getPos(j)});
  }
 }
}
// 获取位置
function getPos(num){
 return 20 + num*120;
}

这样我们的第一层就好了

效果:

现在构造第二层,即构建一个4x4的值全部为0的数组,由于在构造第二层时,有两层循环,所以我们可以在构造第一层时也能构造第二层

第三层是用js生成16个格子,它和第一层的16个格子一一对应

代码:

// 数字格
function numFormat(){
 for(var i=0;i<4;i++){
  for(var j=0;j<4;j++){
   $('#container').append('<div class="number" id="number-'+ i +'-'+ j +'"></div>')
   // 设置数字格的位置,样式
   var everyNumber = $('#number-'+ i +'-'+ j);
   if(checkerboard[i][j] == 0){
    everyNumber.css({
     width:'0px',
     height:'opx',
     top:getPos(i) + 50,
     left:getPos(j) + 50
    })
   }else{
    everyNumber.css({
     width:'100px',
     height:'100px',
     top:getPos(i),
     left:getPos(j),
backgroundColor:getBackgroundColor(checkerboard[i][j]),
     color:getColor(checkerboard[i][j])
    });
    everyNumber.text(checkerboard[i][j]);
   }
  }
 }
}
// 获取相应数字的背景颜色
function getBackgroundColor(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 8192:return "#93c";break;
 }
}
// 设置相应数字的文字颜色
function getColor(number){
 if (number <= 4) {
  return "#776e65"
 }
 return "white";
}

初始化

在每次游戏重新开始时,都会在随机的位置出现两个随机的数字,我们写一个在随机位置出现一个随机数的函数,只要调用两次就可以实现了

代码:

// 随机的在一个位置上产生一个数字
function randomNum(){
 // 随机产生一个坐标值
 var randomX = Math.floor(Math.random() * 4);
 var randomY = Math.floor(Math.random() * 4);
 // 随机产生一个数字(2或4)
 var randomValue = Math.random() > 0.5 ? 2 : 4;
 // 在数字格不为0的地方生成一个随机数字
 while(true){
  if(checkerboard[randomX][randomY] == 0){
   break;
  }else{
   var randomX = Math.floor(Math.random() * 4);
   var randomY = Math.floor(Math.random() * 4);
  }
 }
 // 将随机产生的数字显示在随机的位置上
 checkerboard[randomX][randomY] = randomValue;
 // 动画
 randomNumAnimate(randomX,randomY,randomValue);
}
// 随机产生数字的动画
function randomNumAnimate(randomX,randomY,randomValue){
 var randomnum = $('#number-'+ randomX +'-'+ randomY);
 randomnum.css({
  backgroundColor:getBackgroundColor(randomValue),
  color:getColor(randomValue),
 })
    .text(randomValue)
    .animate({
     width:'100px',
     height:'100px',
     top:getPos(randomX),
     left:getPos(randomY)
    },50);
}

基本操作

我们通过switch循环,来根据用户不同的输入进行不同的操作

代码:

// 获取键盘事件,检测不同的按键进行不同的操作
$(document).keydown(function(event){
 switch(event.keyCode){
  case 37://左
   if(canMoveLeft(checkerboard)){
    // 如果可以向左移动
    MoveLeft();
    // 向左移动
    setTimeout(function(){
     randomNum();
    },200);
    // 随机产生一个数字
   }
   break;
  case 38://上
   if(canMoveUp(checkerboard)){
    // 如果可以向上移动
    MoveUp();
    // 向上移动
    setTimeout(function(){
     randomNum();
    },200);
    // 随机产生一个数字
   }
   break;
  case 39://右
   if(canMoveRight(checkerboard)){
    // 如果可以向右移动
    MoveRight();
    // 向右移动
    setTimeout(function(){
     randomNum();
    },200);
    // 随机产生一个数字
   }
   break;
  case 40://下
   if(canMoveDown(checkerboard)){
    // 如果可以向下移动
    MoveDown();
    // 向下移动
    setTimeout(function(){
     randomNum();
    },200);
    // 随机产生一个数字
   }
   break;
  default:
   break;
 }
});

由于数字格的移动只有左、上、右、下四种方式,并且他们都是大同小异的,所以就拿向左移动为例,

向左移动,我们首先需要判断它是否能向左移动,能向左移动有两种情况

第一种:当前格子的左边的格子是空的即值为0

第二种:当前格子的值和左边格子的值相同

由于向左移动,所以第一列的格子不可能向左移动,所以不需要判断

代码:

// 判断是否可以向左移动
function canMoveLeft(checkerboard){
 for(var i=0;i<4;i++){
  for(var j=1;j<4;j++){
   if(checkerboard[i][j] != 0){
    // 如果这个数字格它左边的数字格为空或者左边的数字格和它相等,则可以向左移动
    if(checkerboard[i][j-1] == 0 || checkerboard[i][j] == checkerboard[i][j-1]){
     return true;
    }
   }
  }
 }
 return false;
}

判断能否向左移动后,我们就要对可以移动的格子进行移动,这里需要特别注意,向哪个方向移动就要先从哪个方向开始判断

代码:

// 向左移动
function MoveLeft(){
 for(var i=0;i<4;i++){
  for(var j=1;j<4;j++){
   if(checkerboard[i][j] != 0){
    for(var k=0;k<j;k++){
     if(checkerboard[i][k] == 0 && noMiddleNumRow(i,k,j,checkerboard)){
      moveAnimation(i,j,i,k);
      checkerboard[i][k] = checkerboard[i][j];
      checkerboard[i][j] = 0;
     }else if(checkerboard[i][k] == checkerboard[i][j] && noMiddleNumRow(i,k,j,checkerboard) && !hasConflicted[i][k]){
      moveAnimation(i,j,i,k);
      checkerboard[i][k] += checkerboard[i][j];
      checkerboard[i][j] = 0;
     }
    }
   }
  }
 }
 // 设置刷新的时间是为了让运动的动画走完在进行更新数字格,否则数字格运动的动画将会被打断
 setTimeout(function(){
  numFormat();
 },200);
}
// 判断中间的数字格是否为0(行)
function noMiddleNumRow(row,col1,col2,checkerboard){
 for(var i=col1+1;i<col2;i++){
  if(checkerboard[row][i] != 0){
   return false;
  }
 }
 return true;
}

将上、右、下四个方向写完以后,游戏基本的操作就已经完成了。

游戏分数和判断游戏结束

游戏的分数是每个相加的数的和,所以我们在每个数相加的时候更新分数就可以了

代码:

// 更新分数
score += checkerboard[k][j];
updateScore(score);
 // 设置分数
function updateScore(num){
 $('#score').text(num);
}

判断游戏是否结束很简单,用我们之前定义的方法就可以实现

代码:

// 判断游戏是否结束
function wheGameOver(checkerboard){
 if(!canMoveLeft(checkerboard) && !canMoveUp(checkerboard) && !canMoveRight(checkerboard) && !canMoveDown(checkerboard) ){
  showGameOver();
 }
}
// 显示游戏结束
function showGameOver(){
 $('#container').append("<div id='gameover'><p>最终得分</p><span>"+ score +"</span><a href='javascript:resert();'>重新开始游戏</a></div> ")
}
// 重新开始游戏
function resert(){
 $('#gameover').remove();
 newgame();
}

最后优化

1、游戏中会出现一次移动,一个数会被累加很多次

在原游戏中,每个数在每次操作中只能累加一次,所以我们在定义一个4x4的值为false的数组,与中间层的数组一一对应,专门用来防止一个数的多次累加,如果是false则可以累加,并将值改为false,否则不可以累加

2、结束死循环

由于在设置随机数的时候用到了一个死循环,但是在游戏结束后,该循环还在,所以我们在死循环中在添加一个条件,如果游戏结束就跳出循环

3、最后的结束游戏提示不执行

case 37://左
   if(canMoveLeft(checkerboard)){
    // 如果可以向左移动
    MoveLeft();
    // 向左移动
    setTimeout(function(){
     wheGameOver(checkerboard)
    },300);
    // 判断游戏是否结束,这里设置延时是因为要等到随机产生数字后再进行判断,如果不加
    // 延时,则最后一次的判断因为canMoveLeft(checkerboard)为false就不会再执行了
    setTimeout(function(){
     randomNum();
    },200);
    // 随机产生一个数字
   }
   break;

从代码中可以看出,判断游戏是否结束是在随机产生一个数字前执行的,所以在判断游戏结束时,总是有一个空的格子,所以代码执行后认为游戏没有结束,但是当这个随机数字产生后,所有的格子不能移动,当我们按键时,if条件不通过,判断游戏是否结束的函数不能执行。所以我们要给判断游戏结束的函数设置定时器,让他在随机产生一个数字后再进行判断

4、在移动端可以执行

由于原作者没有写有关移动端的操作,所以我在网上找的判断移动端触屏手机滑动位置的代码,加入了游戏的事件就可以执行了

//返回角度
   function GetSlideAngle(dx, dy) {
    return Math.atan2(dy, dx) * 180 / Math.PI;
   }
   //根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右,0:未滑动
   function GetSlideDirection(startX, startY, endX, endY) {
    var dy = startY - endY;
    var dx = endX - startX;
    varresult = 0;
    //如果滑动距离太短
    if(Math.abs(dx) < 2 && Math.abs(dy) < 2) {
     returnresult;
    }
    var angle = GetSlideAngle(dx, dy);
    if(angle >= -45 && angle < 45) {
     result = 4;
    }else if (angle >= 45 && angle < 135) {
     result = 1;
    }else if (angle >= -135 && angle < -45) {
     result = 2;
    }
    else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
     result = 3;
    }
    return result;
   }
   //滑动处理
   var startX, startY;
   document.addEventListener('touchstart',function (ev) {
    startX = ev.touches[0].pageX;
    startY = ev.touches[0].pageY;
   }, false);
   document.addEventListener('touchend',function (ev) {
    var endX, endY;
    endX = ev.changedTouches[0].pageX;
    endY = ev.changedTouches[0].pageY;
    var direction = GetSlideDirection(startX, startY, endX, endY);
    switch(direction) {
     case 0:
      //没滑动
      break;
     case 1:
      if(canMoveUp(checkerboard)){
      // 如果可以向上移动
      MoveUp();
      // 向上移动
      setTimeout(function(){
       wheGameOver(checkerboard)
      },300);
      // 判断游戏是否结束
      setTimeout(function(){
       randomNum();
      },200);
      // 随机产生一个数字
      }
      break;
     case 2:
      if(canMoveDown(checkerboard)){
      // 如果可以向下移动
      MoveDown();
      // 向下移动
      setTimeout(function(){
       wheGameOver(checkerboard)
      },300);
      // 判断游戏是否结束
      setTimeout(function(){
       randomNum();
      },200);
      // 随机产生一个数字
      }
      break;
     case 3:
      if(canMoveLeft(checkerboard)){
      // 如果可以向左移动
      MoveLeft();
      // 向左移动
      setTimeout(function(){
       wheGameOver(checkerboard)
      },300);
      // 判断游戏是否结束,这里设置延时是因为要等到随机产生数字后再进行判断,如果不加
      // 延时,则最后一次的判断因为canMoveLeft(checkerboard)为false就不会再执行了
      setTimeout(function(){
       randomNum();
      },200);
      // 随机产生一个数字
      }
      break;
     case 4:
      if(canMoveRight(checkerboard)){
      // 如果可以向右移动
      MoveRight();
      // 向右移动
      setTimeout(function(){
       wheGameOver(checkerboard)
      },300);
      // 判断游戏是否结束
      setTimeout(function(){
       randomNum();
      },200);
      // 随机产生一个数字
      }
      break;
     default:
    }
   }, false);

总结

总体来说这个游戏实现起来并不是太难,就是许多小的操作集合起来

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • 分享20款好玩的jQuery游戏

    今天本文收集了20佳基于jQuery开发的特色游戏,一起来欣赏吧! 1- Tetris with jQuery 2- Game Query- Game engine for jQuery 3- JQuery Snake Game Plugin 4- JQuery Tic Tac Toe 5- jQuery Powered Mine Sweeper 6- Browser Shooter 7- Angel Dreams 8- Sudoku 9- Basic Memory Game with jQue

  • 使用vue.js编写蓝色拼图小游戏

    之前在网上看到<蓝色拼图>这款小游戏,作者是用jquery写的.于是便考虑能不能用vue.js优雅简单的编写出来呢? Later equals never!说干就干.首先理解游戏的规则:第一关为1*1的方块,第二关为2*2以此类推 该图为第三关3*3的方块.点击一个小方块,该方块和它相邻的方块的的颜色会从黄色变为蓝色,全部变为蓝色就过关了. 现在规则清楚了,开动吧! /*style*/ .game_bg{ background: #333; width: 600px; height: 600p

  • 基于Vue.js实现数字拼图游戏

    先来看看效果图: 功能分析 当然玩归玩,作为一名Vue爱好者,我们理应深入游戏内部,一探代码的实现.接下来我们就先来分析一下要完成这样的一个游戏,主要需要实现哪些功能.下面我就直接将此实例的功能点罗列在下了: 1.随机生成1~15的数字格子,每一个数字都必须出现且仅出现一次 2.点击一个数字方块后,如其上下左右有一处为空,则两者交换位置 3.格子每移动一步,我们都需要校验其是否闯关成功 4.点击重置游戏按钮后需对拼图进行重新排序 以上便是本实例的主要功能点,可见游戏功能并不复杂,我们只需一个个攻

  • jQuery实现简易的天天爱消除小游戏

    今天分享一枚小demo:<天天爱消除游戏>,我想大家对这个游戏不陌生吧!?近期挺火的一款手游 妙味的讲师也很喜欢玩这款游戏 ,课余时间就写了个简易版天天的爱消除,除了PC端以外,试试在iPad.iPhone上玩吧~ 涉及知识点:JS.HTML5; 游戏截图: CSS: *{ margin:0; padding:0;} #ul1{ position:relative; margin:20px auto; background:#1b1f2b; overflow:hidden;} #ul1 li{

  • jQuery实现的五子棋游戏实例

    本文实例讲述了jQuery实现的五子棋游戏.分享给大家供大家参考.具体如下: 这是一款非常不错的代码,就是人工智能方面差了一点 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999

  • jQuery实现拼图小游戏(实例讲解)

    小熊维尼拼图 jQuery代码实现拼图小游戏,鼠标选中拼块,用上下左右键移动拼块. html代码 <div id="box-div"> <!--走不通时的提示!--> <div id="tips"> <p>\(╯-╰)/ 哎呦,走不通啦!</p> </div> <div id="container"> <div class="row"&g

  • jQuery+vue.js实现的九宫格拼图游戏完整实例【附源码下载】

    本文实例讲述了jQuery+vue.js实现的九宫格拼图游戏.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> * { margin: 0; padding: 0; } /*#piclist { width: 600p

  • jquery实现的美女拼图游戏实例

    本文实例讲述了jquery实现的美女拼图游戏.分享给大家供大家参考.具体如下: 这里可以自由打乱拼图次序,3*3,4*4等多种组合来进行格数拼图 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8&quo

  • JQuery开发的数独游戏代码

    用了很多Jquery的插件,支持鼠标滚轮选数字.没有什么高深的技术点.工作原因很长时间没有更新了,具体代码都有些记不清了,欢迎大家来拍砖.截图:演示地址:http://demo.jb51.net/js/jsukudo/index.html下载地址:jsukudo20081110v0.3.0.5.zip 下载列表:http://code.google.com/p/jsukudo/downloads/list 用到的JS文件 文件名 出处 说明 blockUI.js http://malsup.co

  • jQuery制作可自定义大小的拼图游戏

    我把大小限制在了3-10之间,实在闲的,或者有自虐倾向的可以试试改下.. 本来准备弄图片上去的,还没弄.. pintu.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/199

  • jQuery制作拼图小游戏

    源代码思路分析: [一]如何生成图片网格,我想到两种方法: (1)把这张大图切成16张小图,然后用img标签的src (2)只有一张大图,然后每个元素的背景图用css的background-position进行切割定位,这样就需要16个数组[0,0],[-150,0],[-300,0]..........(我采用这种) [二]图片背景定位数组与布局定位数组 在选择了使用CSS定位切图,就需要生成数据. 需要的css背景 定位数组为:[0,0],[-150,0],[-300,0],[-450,0]

  • 基于jquery的地址栏射击游戏代码

    演示地址:http://demo.jb51.net/js/2011/hunt/index.htm玩法向下看 请看地址栏上的字母 O! 你使用O来向 a射击. 使用键盘上的 左箭头 和 右箭头 移动字母O. 当O移动到 a 上时,按 空格键射击! 游戏会定时30秒时间,按ESC键重新开始. 注:请使用系统自带的IE浏览器来打开本链接. 你使用O来向 a射击. 使用键盘上的 左箭头 和 右箭头 移动字母O. 当O移动到 a 上时,按 空格键射击! // // 核心代码: 复制代码 代码如下: (fu

随机推荐