zoukankan      html  css  js  c++  java
  • JQuery实现1024小游戏

    最近用Jqery写了一个1024小游戏,由于是第一次写小游戏,所以就选了一个基础的没什么难度游戏。具体实现如下:

    首先在开发时将整个游戏分成两层(自认为),底层是游戏的数据结构以及对数据的操作,上层是显示出来的用户界面。底层选择使用一个4x4的二维数组,整个游戏的数据操作都围绕着这个二维数组进行。

    【一】游戏基础界面

     1 <div id="game">
     2         <div id="header">
     3             <h1>1024</h1>
     4             <button id="newGame">开始新的游戏</button>
     5             <p>分数:<span id="score">0</span>&nbsp;&nbsp;&nbsp;&nbsp;最高分:<span id="maxScore">0</span></p>
     6             <div id="movescore"><p>+16</p></div>
     7         </div>
     8         <div id="container">
     9             <div class="cell" id="cell-0-0"></div>
    10             <div class="cell" id="cell-0-1"></div>
    11             <div class="cell" id="cell-0-2"></div>
    12             <div class="cell" id="cell-0-3"></div>
    13             <div class="cell" id="cell-1-0"></div>
    14             <div class="cell" id="cell-1-1"></div>
    15             <div class="cell" id="cell-1-2"></div>
    16             <div class="cell" id="cell-1-3"></div>
    17             <div class="cell" id="cell-2-0"></div>
    18             <div class="cell" id="cell-2-1"></div>
    19             <div class="cell" id="cell-2-2"></div>
    20             <div class="cell" id="cell-2-3"></div>
    21             <div class="cell" id="cell-3-0"></div>
    22             <div class="cell" id="cell-3-1"></div>
    23             <div class="cell" id="cell-3-2"></div>
    24             <div class="cell" id="cell-3-3"></div>
    25         </div>
    26         <div class="gameover">
    27             <div id="gameoverText">
    28                 <p></p>
    29             </div>
    30             <p id="gameoverScore"></p>
    31             <div id="reStart">
    32                 <button id="reStartBtn">再玩一次</button>
    33             </div>
    34         </div>
    35      </div>

    CSS:

     1 *{
     2             margin: 0;
     3             padding: 0;
     4         }
     5         #game{
     6             font-family: Arial;
     7             margin: 0 auto;
     8             text-align: center;
     9         }
    10         #header{
    11             margin: 20px;
    12         }
    13         #header a{
    14             font-family: Arial;
    15             text-decoration: none;/*设置 h1、h2、h3、h4 元素的文本修饰*/
    16             display: block;
    17             color: white;
    18             margin: 20px auto;
    19             width: 125px;
    20             height: 35px;
    21             text-align: center;
    22             line-height: 40px;
    23             background-color: #8f7a66;
    24             border-radius: 10px;
    25             font-size: 15px;
    26         }
    27         #header p{
    28             font-family: Arial;
    29             font-size: 20px;
    30         }
    31         #container{
    32             width: 460px;
    33             height: 460px;
    34             background-color: #bbada0;
    35             margin: 0 auto;
    36             border-radius: 10px;
    37             position: relative;
    38             padding: 20px;
    39         }
    40         .cell{
    41             width: 100px;
    42             height: 100px;
    43             border-radius: 6px;
    44             background-color: #ccc0b3;
    45             position: absolute;
    46             font-size: 3.5em;
    47             font-weight:700;
    48             text-align: center;
    49             line-height:100px;
    50         }
    51         #newGame{
    52             width: 120px;
    53             height: 30px;
    54             border-radius: 5px;
    55             border: 1px solid rgb(143,122,102);
    56             background-color: rgb(143,122,102);
    57             color: white;
    58             margin-top: 10px;
    59             margin-bottom: 10px;
    60         }
    61         .gameover{
    62             width: 100%;
    63             height: 500px;
    64             background-color: rgba(255,255,255,0.5);
    65             position: absolute;
    66             top:153px;
    67             display: none;
    68         }
    69         #gameoverText{
    70             font-size: 4em;
    71             font-weight: 600;
    72             color:     #363636;
    73             text-align: center;
    74             opacity: 1;
    75             padding-top: 10%;
    76         }
    77         #reStartBtn{
    78             width: 100px;
    79             height: 40px;
    80             border-radius: 5px;
    81             border: 1px solid rgb(143,122,102);
    82             background-color: rgb(143,122,102);
    83             color: white;
    84             margin-top: 3%;
    85         }
    86         #gameoverScore{
    87             font-size: 1.5em;
    88         }
    89         #movescore{
    90             position: absolute;
    91             text-align: center;
    92             padding-left: 45%;
    93             top:110px;
    94             font-weight: 600;
    95             display: none;
    96         }

    此时界面的16个格子是重叠在一起的,给每个格子写css比较麻烦,所以通过js循环进行设置:

    1 //初始化绘制表格
    2 function printTab(){
    3     for(var i=0;i<4;i++){
    4         for(var j=0;j<4;j++){
    5             var cell=$('#cell-'+i+'-'+j);
    6             cell.css({top:(20+i*120),left:(20+j*120)});
    7         }
    8     }
    9 }

    不同的数字显示不同的背景颜色与文字颜色:

     1           function getBackgroundColor(number){
     2                 switch (number) {
     3                     case 2:return "#eee4da";break;
     4                     case 4:return "#ede0c8";break;
     5                     case 8:return "#f2b179";break;
     6                     case 16:return "#f59563";break;
     7                     case 32:return "#f67c5f";break;
     8                     case 64:return "#f65e3b";break;
     9                     case 128:return "#edcf72";break;
    10                     case 256:return "#edcc61";break;
    11                     case 512:return "#9c0";break;
    12                     case 1024:return "#33b5e5";break;
    13                     case 2048:return "#09c";break;
    14                     case 4096:return "#a6c";break;
    15                     case 8192:return "#93c";break;
    16                 }
    17             }
    18             // 设置相应数字的文字颜色
    19             function getColor(number){
    20                 if (number <= 4) {
    21                     return "#776e65"
    22                 }
    23                 return "white";
    24             }

    每次操作后根据当前二维数组进行重绘画面:

     1 //根据二维数组绘制画面
     2 function rePrint(checkerboard){
     3     for(var i=0;i<4;i++){
     4         for(var j=0;j<4;j++){
     5             if(checkerboard[i][j]!=0){
     6                 var printCell=$('#cell-'+i+'-'+j);
     7                 printCell.css('background-color',getBackgroundColor(checkerboard[i][j]));
     8                 printCell.css('color',getColor(checkerboard[i][j]));
     9                 printCell.text(checkerboard[i][j]);
    10                 if(checkerboard[i][j]>=1024){
    11                     printCell.css('font-size','2.5em');
    12                     printCell.css('font-weight','500');
    13                 }
    14             }else{
    15                 var printCell=$('#cell-'+i+'-'+j);
    16                 printCell.css('background-color','#ccc0b3');
    17                 printCell.css('color','black');
    18                 printCell.text('');
    19             }
    20         }
    21     }
    22 }

     【二】游戏逻辑

    除了需要定义一个二维数组checkerboard,还需要定义一个存总分的变量score,一个存每次操作得分的变量addScore,一个记录键盘是否可以操作的变量ableKeyDown,0可以响应键盘操作,1禁止键盘操作。

    ①游戏初始化

    初始化封装成一个函数方便后续的【开始新的游戏】以及【再玩一次】功能。

     1 //初始化游戏        
     2 function newgame(){
     3     ableKeyDown=0;
     4     score=0;
     5     checkerboard=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]];
     6     $('#score').text('0');
     7     $('#maxScore').text(window.localStorage.getItem("maxScore"));
     8     rePrint(checkerboard);
     9     randNum(checkerboard);
    10     randNum(checkerboard);
    11 }

    ②在随即位置生成2或4

    根据游戏规则,在游戏刚开始时会在两个随即位置分别生成2或4,在每次操作后若游戏没结束,会在一个空的位置随机生成一个2或4,将这一功能封装成一个函数,Math.random()生成的随机数范围是[0,1),由于二维数组范围是[0,3],所以通过Math.floor(Math.random()*4)将得到0-3的随机数。另外需要随机得到2或4,定义一个数组initRandNum=[2,4],只需随机得到initRandNum[0]或initRandNum[1]即可,所以同理使用Math.floor(Math.random()*2)随机得到1或2即可。

     1 function randNum(checkerboard){//在随机位置随机产生2或4
     2         var randX = Math.floor(Math.random()*4);
     3         var randY = Math.floor(Math.random()*4);
     4         var initRandNum=[2,4];
     5         var randNum=Math.floor(Math.random()*2);
     6         var randVal=initRandNum[randNum];
     7         while(true){
     8             if(checkerboard[randX][randY]==0){
     9                 break;
    10             }else{
    11                 var randX = Math.floor(Math.random()*4);
    12                 var randY = Math.floor(Math.random()*4);
    13             }
    14         }
    15         checkerboard[randX][randY]=randVal;
    16         printRandNum(randX,randY,randVal);//将randNum()绘制出来
    17 }

    在得到上述随即位置的2或4后需要将其绘制出来:

    1 function printRandNum(randX,randY,randVal){
    2     var printRandCell=$('#cell-'+randX+'-'+randY);
    3     printRandCell.css('background-color',getBackgroundColor(randVal));
    4     printRandCell.css('color',getColor(randVal));
    5     printRandCell.text(randVal);
    6 }

    ③游戏中最重要的两个函数

    即判断当前能否移动的函数以及如何移动合并的函数。

    1)--------判断能否移动,以左移为例

    根据对游戏的观察发现在两中情况下可以移动,一是存在某个不为零的方块,该数字左边为空,即其左边的数组值为0;二是存在某个不为零的方块,,该数字左边与其相同,即其左边的数组值与其相等。对二维数组进行循环,若满足上述条件就返回1,即可以移动。

     1 function canMoveLeft(checkerboard){
     2     for(var i=0;i<4;i++){
     3         for(var j=0;j<4;j++){
     4             if(checkerboard[i][j]!=0){
     5                 if(j!=0){
     6                     if(checkerboard[i][j-1]==0||checkerboard[i][j-1]==checkerboard[i][j]){
     7                         return 1;
     8                         break;
     9                     }
    10                 }
    11             }
    12         }
    13     }
    14 }

    2)--------移动合并函数,以左移为例

    这个应该是游戏中最重要的函数,根据游戏规则,1)若一个非零方块左边全部为空,它将移动到最左边,若左边的某个不为0,它将移动到这个不为0方块的右边;2)若一个非零方块与左边的数字相同,它将移动到左边并与之合并相加;3)若一个非零方块与左边的数字相同,他与左边合并后的值恰巧与再左边的数相同,此时应该只进行第一次合并,不进行第二次合并。例如当前一排是4,2,2,0,其移动后结果应该是4,4,0,0,而不是8,0,0,0。

    第三点尤为重要,最开始由于忽略了这点写出来后结果是不对的。我真对3)的解决办法是,在每次循环一行时初始化一个长度为4的数组var tag=[0,0,0,0],若某个数在此次循环制相加过一次,就在tag相应位置置为1,再然后在每次合并前做一次判断,若该tag为1,则不进行相加。

     1 function moveLeft(checkerboard){
     2     addscore=0;
     3     for(var i=0;i<4;i++){
     4         var tag=[0,0,0,0];
     5         for(var j=1;j<4;j++){ 7             if(checkerboard[i][j]!=0){                        
     8                 if(checkerboard[i][j-1]==0){//左边为空时
     9                     for(k=j-1;k>=0;k--){
    10                         if(checkerboard[i][k]!=0){
    11                             checkerboard[i][k+1]=checkerboard[i][j];
    12                             checkerboard[i][j]=0;
    13                             if(checkerboard[i][k+1]==checkerboard[i][k]){//移动后与左边相等
    14                                 if(tag[k]==0&&tag[k+1]==0){
    15                                     checkerboard[i][k]+=checkerboard[i][k+1];
    16                                     score += checkerboard[i][k];
    17                                     addscore+=checkerboard[i][k];
    18                                     tag[k]=1;20                                     checkerboard[i][k+1]=0;
    21                                 }
    22                             }
    23                             break;
    24                         }else if(k==0){//左边全空
    25                             checkerboard[i][0]=checkerboard[i][j];
    26                             checkerboard[i][j]=0;
    27                             break;
    28                         }
    29                     }
    30                 }else if(checkerboard[i][j-1]==checkerboard[i][j]){//左边相等时
    31                     if(tag[j-1]==0&&tag[j]==0){
    32                         checkerboard[i][j-1]+=checkerboard[i][j];
    33                         score += checkerboard[i][j-1];
    34                         addscore+=checkerboard[i][j-1];
    35                         tag[j-i]=1;37                         checkerboard[i][j]=0;
    38                     }    
    39                 }    
    40             }
    41         }
    42     }
    43     rePrint(checkerboard);//停止移动后重绘画面
    44 }

    值得注意的是,为了计算游戏的总分以及每次操作的得分,需要在每次合并后对addScore和score进行计算。

    右移、上移、下移与左移逻辑基本相同,只需对左移代码稍作修改即可。

    ④关于分数

    1 //更新分数
    2 function updateScore(num){
    3     $('#score').text(num);
    4 }

    在每次得分后会在总分位置产生一个加分动画

     1 //分数动画            
     2 function movescore(score){
     3     if(score>0){
     4         $('#movescore p').text('+'+score);
     5         $('#movescore').css('top','110px');
     6         $('#movescore').show();
     7         var top;
     8         var topVal=110;
     9         var opacityVal=1;
    10         var timer=null;
    11         timer=setInterval(function(){
    12             topVal-=5;
    13             opacityVal-=0.1;
    14             top=topVal+'px';
    15             $('#movescore').css('top',top);
    16             $('#movescore').css('opacity',opacityVal);
    17             if(topVal<50){
    18                 clearInterval(timer);
    19                 $('#movescore').hide();
    20             }
    21         },40);
    22     }            
    23 }

    ⑤游戏结束

    若二维数组中某一项等于1024游戏结束,显示最终得分,并设置键盘不可继续操作;或者当前无法继续移动游戏结束,显示最终得分。

     1 //游戏结束函数
     2 function gameOver(checkerboard){
     3     if(canMoveLeft(checkerboard)!=1&&canMoveRight(checkerboard)!=1&&canMoveUp(checkerboard)!=1&&canMoveDown(checkerboard)!=1){
     4         $('.gameover').show();
     5         $('#gameoverText p').text('Game Over !');
     6         $('#gameoverScore').text('最终得分'+score);
     7         if(score>window.localStorage.getItem("maxScore")){
     8             window.localStorage.setItem("maxScore",score);
     9             $('#maxScore').text(window.localStorage.getItem("maxScore"));
    10         }
    11     }
    12     for(var i=0;i<4;i++){
    13         for(var j=0;j<4;j++){
    14             if(checkerboard[i][j]==1024){
    15                 ableKeyDown=1;//键盘不可操作
    16                 $('.gameover').show();
    17                 $('#gameoverText p').text('Congratulations!');
    18                 $('#gameoverScore').text('最终得分'+score);
    19                 if(score>window.localStorage.getItem("maxScore")){
    20                     window.localStorage.setItem("maxScore",score);
    21                     $('#maxScore').text(window.localStorage.getItem("maxScore"));
    22                 }
    23                 break;
    24             }
    25         }
    26     }
    27 }

    ⑥开始新游戏&再玩一次

    1 //开始新游戏
    2 $('#newGame').click(function(){
    3     newgame();
    4 });
    5 //再玩一次
    6 $('#reStartBtn').click(function(){
    7     $('.gameover').hide();
    8     newgame();
    9 });
  • 相关阅读:
    圆周率的计算与进度条
    Python的使用方法
    Python科学计算库
    linux 命令总结[转]
    如何在 Windows 平台上下載 Android 的源码[转]
    装MSN报错问题解决 无法定位程序输入点except handler4 common 于动态链接库nsvcrt.dll【转】
    编写xorg.conf,简单三行解决ubuntu分辩率不可调的问题【转】
    谁说 Android 手机一定要 root 权限才能截屏?![转]
    给自己的忠告[转]
    lockdir加密bug[转]
  • 原文地址:https://www.cnblogs.com/huangin/p/9503006.html
Copyright © 2011-2022 走看看