演示以及原理讲解
源码地址: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站搜索“我们一起学前端”