我也来一个“羊了个羊”

演示以及原理讲解

 

 

源码地址: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站搜索“我们一起学前端”

  • 22
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值