• 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 });
  • 相关阅读:
    手把手教你利用create-nuxt-app脚手架创建NuxtJS应用
    初识NuxtJS
    webpack打包Vue应用程序流程
    用选择器代替表格列的筛选功能
    Element-UI
    Spectral Bounds for Sparse PCA: Exact and Greedy Algorithms[贪婪算法选特征]
    Sparse Principal Component Analysis via Rotation and Truncation
    Generalized Power Method for Sparse Principal Component Analysis
    Sparse Principal Component Analysis via Regularized Low Rank Matrix Approximation(Adjusted Variance)
    Truncated Power Method for Sparse Eigenvalue Problems
  • 原文地址:https://www.cnblogs.com/huangin/p/9503006.html
Copyright © 2020-2023  润新知