• 我也来一个“羊了个羊”


    演示以及原理讲解

     

     

    源码地址:https://gitee.com/13026118978/sheep-asheep

    实现

    1.定义变量

    // 动物数组 const animals = [ "🐔", "🐟", "🦆", "🐶", "🐱", "🐴", "🐑", "🐦", "🐧", "🐊", "🐺", "🐒", "🐳", "🐬", "🐢", "🦖", "🦒", "🦁", "🐍", "🐭", "🐂", ];

    export const configData = { 

          animals,  // 动物数组

          chessCellNum:24, // 棋盘格子数 

          SizePerCell:14,// 棋盘每个格子宽高 

          typeNum: 12,  // 动物类别数 

          slotNum: 7,// 槽容量 

          composeNum: 3, // 可以合成的数量

          levelNum:6, // 总层数

          blockNumPerLevel:48, // 每一层的块数 

          randomBlocks:[8,8], // 随机区

          shrinkNum:1,// 边界收缩单位 

    }

    let levelBlockList = []; // 层级块数组

    let randomBlockList = []   // 随机块数组

    let slotBlockList = []  // 插槽数组

    let chessBoard;   // 棋盘,存储每个格子里装的层级块

    let clearNum = 0 ; // 消除的数量 

    let totalNums = 0 ;  // 总的块数

    2.初始化棋盘

    给棋盘分格子,每个格子加一个blocks属性,保存块数据

    function initChessBoard(){

           chessBoard = new Array(configData.chessCellNum) 

           for(let i = 0 ; i < configData.chessCellNum ; i++){ 

                    chessBoard[i] = new Array(configData.chessCellNum) 

                    for(let j = 0 ; j < configData.chessCellNum ; j++){ 

                            chessBoard[i][j] = { blocks:[] }

                    }

           }

    }

    3.初始化游戏数据

         ①计算出块的单位数

    let unitBlockNum = configData.typeNum * configData.composeNum;

         ②算出随机块的总数

    let randomTotalBlock = 0 ;

    configData.randomBlocks.forEach(num=>{ randomTotalBlock += num;  })

         ③算出需要的最小块数

    const minBlockNum = configData.levelNum*configData.blockNumPerLevel + randomTotalBlock;

         ④算出总块数

    【总块数需要是 单位块数的倍数,才能最终把所有的图片消除完】

    let totalBlockNum = minBlockNum;

    if(totalBlockNum % unitBlockNum !==0){ 

           totalBlockNum = (Math.floor(totalBlockNum / unitBlockNum)+1)*unitBlockNum; 

    }

    totalNums = totalBlockNum; 

         ⑤根据配置,取出哪些动物将在游戏中出现

    let animalsWillInGame = configData.animals.slice(0,configData.typeNum);

    ⑥根据总数,保存和总数数量一样的动物【报数法  或  分组法】

    let num = totalBlockNum / configData.typeNum

    let allAnimalList = []

    for(let i = 0  ; i < configData.typeNum ; i++){

        for(let j = 0 ; j < num ; j++){

             allAnimalList.push(animalsWillInGame[i])

        }

    }

    let allAnimalList = [];

    for(let i = 0 ; i < totalBlockNum ; i++){ 

          allAnimalList.push(animalsWillInGame[i % configData.typeNum]) 

    }

    0  1  2  3  4  5  6  7  8     9

    鸡 鸭鱼 鸡鸭鱼鸡鸭鱼     3    9 /3 = 3

    0  1  2   0  1  2  0  1  2 

         ⑦打乱数组

    function shuffle(arr){

          let length= arr.length; 

          //while执行至条件不成立则跳出循环

          while(length ]]> 1){ 

                let index = Math.floor(Math.random() * length--); 

                 //es6的解构赋值,等号的左右两边模式相同,就会将右边的值赋给左边的变量

                 [arr[length-1], arr[index]] = [arr[index], arr[length-1]];  }

                 return arr; 

          }

         ⑧初始化块数据

    let allBlocks = []

    for(let i = 0 ; i < totalBlockNum ; i++){ 

         let newBlock = { 

                 id:i,

                 status:0, //0-未点击 1-已点击 2-已消除

                 level:0,

                 animal:AllAnimalList[i],

                 onMyUp:[],

                // 在我上面的块

                onMyDown:[]

                // 在我下面的块  

    }

    allBlocks.push(newBlock) }

       

      ⑨生成随机块数据

    let position = 0 ;

    configData.randomBlocks.forEach((item,index)=>{

                 randomBlockList[index] = [];

                 for(let j = 0 ; j < item ; j++){ 

                          randomBlockList[index].push(allBlocks[position])

                          position++;

                 }

    })

         ⑩生成层叠块数据

    for(let i = 0 ; i < configData.levelNum ; i++){

           // 剩余的块数

           let leaveBlock = totalBlockNum - randomTotalBlock; 

           // 当前层级包括的块数

           let currLevelBlockNum = Math.min(leaveBlock,configData.blockNumPerLevel); 

           // 取出当前层级包括的块

           let currLevelBlock = allBlocks.slice(position,position+currLevelBlockNum); 

           position +=currLevelBlockNum 

           leaveBlock -=currLevelBlockNum 

           // 放入层级数组中

           levelBlockList.push(...currLevelBlock)    

    a.处理每个块的坐标

    let minX = 0;       

    let maxX = 22;       

    let minY = 0;       

    let maxY = 22;       

    // 对范围进行收缩(四个边进行收缩:上右下左)      

    let indexNum = i % 4       

    if(i > 0 ){                

    if(indexNum===0){                       maxY -=configData.shrinkNum;  }                else if(indexNum===1){                        maxX -=configData.shrinkNum;  }                else if(indexNum===2){                         minY +=configData.shrinkNum;  }                else{

                                                            minX +=configData.shrinkNum;  }     

    }     

    dealCoordinate(currLevelBlock,minX,maxX,minY,maxY) }

    function dealCoordinate(currLevelBlock,minX,maxX,minY,maxY){

             let tempObj = {};// 用于去重 

             for(let i = 0 ; i < currLevelBlock.length ; i++){ 

                        let block = currLevelBlock[i]; 

                        let newBlockX ;  let newBlockY ; 

                        let key;

                        // 通过循环获取没有重复的点

                        while(true){

                                 newBlockX = Math.floor(Math.random()*(maxX - minX) + minX) 

                                 newBlockY = Math.floor(Math.random()*(maxY - minY) + minY) 

                                 key = newBlockX+","+newBlockY 

                                 if(!tempObj[key]){

                                     // 之前没有存入这个坐标,则坐标有效

                                     break;

                                 }

                        }

                        // 将块存入棋盘格子中

                      chessBoard[newBlockX][newBlockY].blocks.push(block)

                      tempObj[key] = block; 

                      block.x = newBlockX; 

                      block.y = newBlockY;  

                      // 处理块的关系

                     dealBlockRelative(block)

           }

    }

     b.处理块之间的层级关系

    let maxLevel = 0 ;

    function dealBlockRelative(block){ 

            // 确定与当前块相交的块所占格子坐标[结合格子图去理解]

            let minX = Math.max(block.x - 2 , 0 ); 

            let minY = Math.max(block.y - 2 , 0 ); 

            let maxX = Math.min(block.x + 2, configData.chessCellNum -3) 

            let maxY = Math.min(block.y + 2, configData.chessCellNum -3) 

           // 遍历当前块附近的块,找出最高的块的层级

           for(let i = minX ; i <= maxX ; i++){ 

                  for(let j = minY ; j <= maxY ; j++){ 

                           let relativeBlock = chessBoard[i][j].blocks; 

                           if(relativeBlock.length]]>0){

                                  let maxLevelBlock = relativeBlock[relativeBlock.length - 1];  

                                 // 排除自己

                                 if(maxLevelBlock.id === block.id){  continue; }

                                 // 找到最高层block

                                maxLevel = Math.max(maxLevel,maxLevelBlock.level); 

                                 // 上下层的关系

                                block.onMyDown.push(maxLevelBlock);

                                maxLevelBlock.onMyUp.push(block);

                           }

                   }

            }

            // 设置当前块是所有相交的块中,层级最高的

            block.level = maxLevel + 1; 

    }

    4.开发页面

     

     

    5.处理点击事件

     

     

     

    更多学习视频学习资料请参考:B站搜索“我们一起学前端”

  • 相关阅读:
    一次 Java log4j2 漏洞导致的生产问题
    iOS视频流采集概述(AVCaptureSession)
    动态代理(CGlib和jdk)
    JAVA面试题总结基础篇(三)
    css3中有哪些伪选择器?
    动态规划c++
    期货十三篇 第一篇 警示篇
    企业想要做好数据分析,可以试试瓴羊Quick BI
    基金管理人的内部控制
    雅思口语的具体步骤和时间安排是什么样的?
  • 原文地址:https://blog.csdn.net/qq_35577655/article/details/127468472