import { _decorator, Component, instantiate, Node, Prefab, Sprite, tween, UIOpacity, v3, Vec3, view } from 'cc'; import { BlockController } from './Block/BlockController'; import { BlockBaData, BlockConfig, BlocksAll, BlockState, BlockType, BlockWeights, ReConfig } from './Block/BlockData'; import GlobalData from './GlobalData'; import { LocalStorageMgr } from './LocalStorageMgr'; import { MainGameLogic } from './MainGameLogic'; import { TouchMgr } from './TouchMgr'; import { AudioManager } from '../AudioManager'; import { Url } from '../Url'; import ResSprite from '../ResSprite'; const { ccclass, property } = _decorator; @ccclass('GridBlockMgr') export class GridBlockMgr extends Component { /** 单例模式 */ private static _ins: GridBlockMgr; constructor() { super(); GridBlockMgr._ins = this; } public static get ins(): GridBlockMgr { if (!GridBlockMgr._ins) { GridBlockMgr._ins = new GridBlockMgr(); } return GridBlockMgr._ins; } @property(Prefab) block: Prefab = null; @property(Node) gridcontainer: Node = null; @property(Node) selects: Node[] = []; @property(Node) SelectionContainer: Node = null; private boardSize: number = 8; private cellSize: number = 122.5; block_ba_data: BlockBaData[][]; temp_block_ba_data: BlockBaData[][]; temp_block_ba_data1: BlockBaData[][]; selection_block_type: BlockType[]; selection_block_config: BlockConfig[] protected onLoad(): void { this.temp_block_ba_data = this.initializeBlockData(); this.temp_block_ba_data1 = this.initializeBlockData(); } async start() { } protected update(dt: number): void { } // 初始化 temp_block_ba_data 的方法 initializeBlockData(): BlockBaData[][] { const size = 8; // 根据实际情况设置 const data: BlockBaData[][] = []; for (let i = 0; i < size; i++) { const row: BlockBaData[] = []; for (let j = 0; j < size; j++) { row.push({ block_state: BlockState.HIDE, block_ba_node: null, // 根据实际情况初始化 index_i: i, index_j: j, block_sprite: null, // 根据实际情况初始化 block_color: Url.BLOCK.ORANGE }); } data.push(row); } return data; } // 检测消除 checkAndUpdateBlocks(): Vec3 | null { const size = 8; const rowsToClear = new Set(); const colsToClear = new Set(); let anyCleared = false; let eliminNum = 0; // 消除的总块数 let totalRow = 0; // 累积的行索引总和 let totalCol = 0; // 累积的列索引总和 let clearedRowCount = 0; // 消除的行数 let clearedColCount = 0; // 消除的列数 // 检查每一行 for (let i = 0; i < size; i++) { let rowAllOnes = true; for (let j = 0; j < size; j++) { if (this.block_ba_data[i][j].block_state !== BlockState.SHOW) { rowAllOnes = false; break; } } if (rowAllOnes) { rowsToClear.add(i); anyCleared = true; clearedRowCount++; } } // 检查每一列 for (let j = 0; j < size; j++) { let colAllOnes = true; for (let i = 0; i < size; i++) { if (this.block_ba_data[i][j].block_state !== BlockState.SHOW) { colAllOnes = false; break; } } if (colAllOnes) { colsToClear.add(j); anyCleared = true; clearedColCount++; } } let centerX = null; let centerY = null; let centerPosition: Vec3 = null; // 统一处理需要消除的行和列 rowsToClear.forEach((i) => { for (let j = 0; j < size; j++) { const node = this.block_ba_data[i][j].block_ba_node; node.getComponent(UIOpacity).opacity = 0; this.block_ba_data[i][j].block_state = BlockState.HIDE; MainGameLogic.ins.createOneBlockEfEffect(node, this.block_ba_data[i][j].block_color); eliminNum++; totalRow += i; totalCol += j; } }); colsToClear.forEach((j) => { for (let i = 0; i < size; i++) { const node = this.block_ba_data[i][j].block_ba_node; node.getComponent(UIOpacity).opacity = 0; this.block_ba_data[i][j].block_state = BlockState.HIDE; MainGameLogic.ins.createOneBlockEfEffect(node, this.block_ba_data[i][j].block_color); eliminNum++; totalRow += i; totalCol += j; } }); if (anyCleared) { AudioManager.ins.playOneShot(Url.AUDIO.SFX10, 1); // 计算最中间块的索引位置 centerX = Math.floor(totalRow / eliminNum); centerY = Math.floor(totalCol / eliminNum); // 获取最中间块的实际位置 const centerNode: Node = this.block_ba_data[centerX][centerY].block_ba_node; centerPosition = centerNode.getPosition(); // 获取世界坐标 // 将消除的行数和列数相加,传递给 detectGuideAndElimiTimes // console.log(clearedRowCount, clearedColCount); const totalClearedLines = clearedRowCount + clearedColCount; MainGameLogic.ins.detectGuideAndElimiTimes(totalClearedLines); // MainGameLogic.ins.getElimitateCash(); // console.log('消除格子数', eliminNum); // console.log('最中间块坐标', centerPosition); let baseScore = mtec.number.random(GlobalData.addScoreFloor, GlobalData.addScoreUp); MainGameLogic.ins.createConsecutiveEffect(centerPosition, totalClearedLines); this.scheduleOnce(() => { MainGameLogic.ins.createEleAddScoreEff(centerPosition, baseScore * eliminNum); }, 1) } this.scheduleOnce(() => { this.saveCurrentBoardState(); }, 1) // 返回最中间块的世界坐标 return centerPosition; } /** 保存当前地图数据的方法 */ saveCurrentBoardState(): void { const size = 8; const currentBoardData = []; for (let i = 0; i < size; i++) { const row = []; for (let j = 0; j < size; j++) { row.push(this.block_ba_data[i][j].block_state === BlockState.SHOW ? 1 : 0); } currentBoardData.push(row); } LocalStorageMgr.setItem(LocalStorageMgr.lastGameBoardData_key, currentBoardData) } // 检测棋盘相连区域,并将最多块数的区域消除-----道具使用 chechBlockArea() { // 根据this.block_ba_data棋盘数据,检测格子相互之间相连的区域 // 计算每个区域相邻的格子有多少,得出格子最最多的区域,将这个区域的格子全部隐藏(消除) // 定义方向数组,用于移动上下左右四个方向 const directions = [ { x: 0, y: 1 }, // 上 { x: 1, y: 0 }, // 右 { x: 0, y: -1 }, // 下 { x: -1, y: 0 } // 左 ]; // 用于记录已经访问过的格子 const visited = new Array(this.boardSize).fill(false).map(() => new Array(this.boardSize).fill(false)); let maxArea = 0; let maxAreaBlocks: BlockBaData[] = []; // 深度优先搜索,检测相连区域 const dfs = (i: number, j: number, currentBlocks: BlockBaData[]) => { visited[i][j] = true; currentBlocks.push(this.block_ba_data[i][j]); for (const direction of directions) { const newRow = i + direction.x; const newCol = j + direction.y; if ( newRow >= 0 && newRow < this.boardSize && newCol >= 0 && newCol < this.boardSize && !visited[newRow][newCol] && this.block_ba_data[newRow][newCol].block_state === BlockState.SHOW ) { dfs(newRow, newCol, currentBlocks); } } }; // 遍历棋盘,找到所有区域 for (let i = 0; i < this.boardSize; i++) { for (let j = 0; j < this.boardSize; j++) { if ( !visited[i][j] && this.block_ba_data[i][j].block_state === BlockState.SHOW ) { const currentBlocks: BlockBaData[] = []; dfs(i, j, currentBlocks); if (currentBlocks.length > maxArea) { maxArea = currentBlocks.length; maxAreaBlocks = currentBlocks; } } } } // 消除最大区域的格子 for (const block of maxAreaBlocks) { block.block_ba_node.getComponent(UIOpacity).opacity = 0; block.block_state = BlockState.HIDE; } // console.log('最大区域的格子数:', maxArea); // console.log('消除的格子:', maxAreaBlocks); } // 检查并消除2x2区域,并返回消除区域的中心坐标 chechAndEliminateRandomArea(): boolean { const regions: { blocks: BlockBaData[], row: number, col: number }[] = []; // 遍历棋盘,以2x2区域为单位进行划分 for (let i = 0; i < this.boardSize; i += 4) { for (let j = 0; j < this.boardSize; j += 4) { const currentRegion: BlockBaData[] = []; // 遍历当前2x2区域的格子 for (let x = i; x < i + 4; x++) { for (let y = j; y < j + 4; y++) { if (this.block_ba_data[x][y].block_state === BlockState.SHOW) { currentRegion.push(this.block_ba_data[x][y]); } } } // 如果该区域内有显示状态的格子,记录下来 if (currentRegion.length > 0) { regions.push({ blocks: currentRegion, row: i, col: j }); } } } // 如果没有找到任何显示状态的区域,直接返回 null if (regions.length === 0) { // console.log('没有区域内有格子处于显示状态'); MainGameLogic.ins.propInUse = false; MainGameLogic.ins.createOneTipTpast('game_tip_noblock') return false; } // 随机选择一个区域 const randomIndex = Math.floor(Math.random() * regions.length); const selectedRegion = regions[randomIndex]; // 计算四个格子中心位置的平均值 let centerX = 0, centerY = 0, centerZ = 0; for (const block of selectedRegion.blocks) { const position = block.block_ba_node.getPosition(); centerX += position.x; centerY += position.y; centerZ += position.z; } const centerPosition = new Vec3(centerX / selectedRegion.blocks.length, centerY / selectedRegion.blocks.length, centerZ / selectedRegion.blocks.length); let fun = () => { // 消除选中区域的格子 for (const block of selectedRegion.blocks) { block.block_ba_node.getComponent(UIOpacity).opacity = 0; block.block_state = BlockState.HIDE; MainGameLogic.ins.createOneBlockEfEffect(block.block_ba_node, block.block_color); } MainGameLogic.ins.propInUse = false; // console.log(`消除了区域 [${selectedRegion.row}, ${selectedRegion.col}] 内的格子`); } this.saveCurrentBoardState(); // MainGameLogic.ins.usePropHummerEffect(centerPosition, fun) return true; } // 根据数据设置棋盘格子 async generateBoard(_boardData) { // 初始化block_ba_data二维数组 this.block_ba_data = []; for (let i = 0; i < this.boardSize; i++) { this.block_ba_data[i] = []; for (let j = 0; j < this.boardSize; j++) { let state = _boardData[i][j]; let name = (i + 1) + '_' + (j + 1); let _block_ba = this.gridcontainer.getChildByName(name); _block_ba.getComponent(UIOpacity).opacity = state == 1 ? 255 : 0; _block_ba.getComponent(ResSprite).setSpriteFrame(Url.BLOCK.ORANGE + '/spriteFrame'); // 创建BlockBaData对象并赋值 const blockBaData: BlockBaData = { index_i: i, index_j: j, block_ba_node: _block_ba, block_state: state == 1 ? BlockState.SHOW : BlockState.HIDE, block_sprite: _block_ba.getComponent(ResSprite), block_color: Url.BLOCK.ORANGE }; // 将blockBaData对象保存到block_ba_data二维数组中 this.block_ba_data[i][j] = blockBaData; } } } // 根据数据设置棋盘格子_带效果 async generateBoard_effect(_boardData) { // 播放音效 AudioManager.ins.playOneShot(Url.AUDIO.SFX12, 1); // 初始化block_ba_data二维数组,快速完成初始化,没有延迟 this.block_ba_data = []; for (let i = 0; i < this.boardSize; i++) { this.block_ba_data[i] = []; for (let j = 0; j < this.boardSize; j++) { let name = (i + 1) + '_' + (j + 1); let _block_ba = this.gridcontainer.getChildByName(name); // 创建BlockBaData对象并初始化状态为隐藏 const blockBaData: BlockBaData = { index_i: i, index_j: j, block_ba_node: _block_ba, block_state: BlockState.HIDE, block_sprite: _block_ba.getComponent(ResSprite), block_color: Url.BLOCK.ORANGE }; // 将blockBaData对象保存到block_ba_data二维数组中 this.block_ba_data[i][j] = blockBaData; } } // 设置透明度的逐行显示效果,添加延迟 for (let i = this.boardSize - 1; i >= 0; i--) { for (let j = 0; j < this.boardSize; j++) { let _block_ba = this.block_ba_data[i][j].block_ba_node; tween(_block_ba.getComponent(UIOpacity)) .to(0.1, { opacity: 255 }) // 显示块 .start(); } // 等待一段时间以便逐行显示 await this.delay(100); // 可以调整延迟时间 } // 根据数据设置状态,并从最上面一行开始逐行隐藏state为0的块 for (let i = 0; i < this.boardSize; i++) { for (let j = 0; j < this.boardSize; j++) { let state = _boardData[i][j]; this.block_ba_data[i][j].block_state = state == 1 ? BlockState.SHOW : BlockState.HIDE; // 如果状态是隐藏,调整透明度 if (state == 0) { let _block_ba = this.block_ba_data[i][j].block_ba_node; tween(_block_ba.getComponent(UIOpacity)) .to(0.1, { opacity: 0 }) // 隐藏块 .start(); } } // 等待一段时间以便逐行隐藏 await this.delay(100); // 可以调整延迟时间 } // 保存当前的棋盘状态 this.saveCurrentBoardState(); } // 延迟函数 delay(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } // 更新棋盘 updateBoard() { for (let i = 0; i < this.block_ba_data.length; i++) { for (let j = 0; j < this.block_ba_data[i].length; j++) { let state = this.block_ba_data[i][j].block_state this.block_ba_data[i][j].block_ba_node.getComponent(UIOpacity).opacity = state == 1 ? 255 : 0; } } } // 根据权重随机返回一个图块数据 getRandomBlockConfig(): BlockConfig | undefined { let totalWeight = 0; const cumulativeWeights: { type: BlockType, weight: number }[] = []; // 累积权重 for (const type in BlockWeights) { if (BlockWeights.hasOwnProperty(type)) { const blockType = Number(type) as BlockType; const weight = BlockWeights[blockType]; totalWeight += weight; cumulativeWeights.push({ type: blockType, weight: totalWeight }); } } const random = Math.random() * totalWeight; let selectedType: BlockType | undefined = undefined; let low = 0; let high = cumulativeWeights.length - 1; // 二分查找 while (low <= high) { const mid = Math.floor((low + high) / 2); if (random < cumulativeWeights[mid].weight) { selectedType = cumulativeWeights[mid].type; high = mid - 1; } else { low = mid + 1; } } if (selectedType !== undefined) { const filteredBlocks = BlocksAll.filter(block => block.block_type === selectedType); // console.log('Filtered Blocks:', filteredBlocks); if (filteredBlocks.length > 0) { const randomIndex = Math.floor(Math.random() * filteredBlocks.length); let colorIandU = mtec.number.random(0, 6, 0); switch (colorIandU) { case 0: filteredBlocks[randomIndex].block_color = Url.BLOCK.BLUE; break; case 1: filteredBlocks[randomIndex].block_color = Url.BLOCK.DEEPBLUE; break; case 2: filteredBlocks[randomIndex].block_color = Url.BLOCK.GREEN; break; case 3: filteredBlocks[randomIndex].block_color = Url.BLOCK.ORANGE; break; case 4: filteredBlocks[randomIndex].block_color = Url.BLOCK.PURPLE; break; case 5: filteredBlocks[randomIndex].block_color = Url.BLOCK.RED; break; case 6: filteredBlocks[randomIndex].block_color = Url.BLOCK.YELLOW; break; default: filteredBlocks[randomIndex].block_color = Url.BLOCK.BLUE; break; } return filteredBlocks[randomIndex]; } } return undefined; } /** * 选择区刷新生成三个图块 * @param isPropFrash 是否使用道具刷新-用作效果判断 * @param blockConfig 是否指定块,传块配置 */ generateSelectionBlock(isPropFrash: boolean, blockConfig?: BlockConfig[]) { let configs = []; if (blockConfig) { for (let i = 0; i < blockConfig.length; i++) { configs.push(blockConfig[i]); TouchMgr.ins.selectCanTouch[i] = true; } } else { for (let i = 0; i < 3; i++) { configs.push(GridBlockMgr.ins.getRandomBlockConfig()) TouchMgr.ins.selectCanTouch[i] = true; } } if (isPropFrash) { this.selects.forEach((block, index) => { tween(block) .to(0.2, { scale: v3(0, 0, 1) }) .call(() => { const blockConfig = configs[index]; block.setPosition(new Vec3(0, 0, 0)) block.getComponent(BlockController).updateBlockSet(true, blockConfig); block.getComponent(BlockController).addBlockOffset(4); block.active = true }) .to(0.2, { scale: v3(0.5, 0.5, 1) }) .start() }) MainGameLogic.ins.propInUse = false; } else { this.SelectionContainer.setPosition(v3(view.getVisibleSize().width, 0, 0)) this.SelectionContainer.setScale(0, 0, 1); tween(this.SelectionContainer) .parallel( tween().to(0.5, { position: v3(0, 0, 0) }), tween().to(0.5, { scale: v3(1, 1, 1) }) ) .start() this.selects.forEach((block, index) => { const blockConfig = configs[index]; block.setPosition(new Vec3(0, 0, 0)) block.getComponent(BlockController).updateBlockSet(true, blockConfig); block.getComponent(BlockController).addBlockOffset(4); block.active = true }) } this.detectSelectsBlockCanUse(true); } // 选择区生成引导图块 generareGuideSelectionBlock(blockConfig: BlockConfig[]) { let configs = []; for (let i = 0; i < blockConfig.length; i++) { configs.push(blockConfig[i]); } this.selects.forEach((block, index) => { const blockConfi = configs[index]; block.setPosition(new Vec3(0, 0, 0)) block.getComponent(BlockController).updateBlockSet(true, blockConfi); block.getComponent(BlockController).addBlockOffset(4); block.active = index == 0 || index == 2 ? false : true; }) TouchMgr.ins.selectCanTouch = [false, true, false]; } // 重置 temp_block_ba_data resetTempBlockData() { for (let i = 0; i < this.block_ba_data.length; i++) { for (let j = 0; j < this.block_ba_data[i].length; j++) { this.temp_block_ba_data[i][j] = { index_i: this.block_ba_data[i][j].index_i, index_j: this.block_ba_data[i][j].index_j, block_state: this.block_ba_data[i][j].block_state, block_ba_node: this.block_ba_data[i][j].block_ba_node, block_sprite: this.block_ba_data[i][j].block_ba_node.getComponent(ResSprite), block_color: this.block_ba_data[i][j].block_color }; } } } // 获取选择区的图块数据,用于检测游戏结束 getSelectionBlockConfig() { this.selection_block_config = []; // 清空之前的配置 for (let i = 0; i < TouchMgr.ins.selectCanTouch.length; i++) { if (TouchMgr.ins.selectCanTouch[i]) { const element = this.selects[i].getComponent(BlockController).curBlockConfig; this.selection_block_config.push(element); } } } // 检测游戏结束, 结束返回 true,否则返回 false detectGameOver(): boolean { this.detectSelectsBlockCanUse(false); this.getSelectionBlockConfig(); const results_block_config: BlockConfig[] = []; if (GlobalData.isRotate) { // 根据 this.selection_block_config 里的 block_type,从 blocks 中找到所有对应的 BlockConfig,存到 results 里 for (let i = 0; i < this.selection_block_config.length; i++) { const blockType = this.selection_block_config[i]; // results_block_config.push(blockType); for (let j = 0; j < BlocksAll.length; j++) { if (BlocksAll[j].block_type === blockType.block_type) { results_block_config.push(BlocksAll[j]); } } } } else { for (let i = 0; i < this.selection_block_config.length; i++) { results_block_config.push(this.selection_block_config[i]) } } // console.log(results_block_config); // 循环遍历results里的BlockConfig能不能放置 for (let i = 0; i < this.block_ba_data.length; i++) { for (let j = 0; j < this.block_ba_data[i].length; j++) { for (let k = 0; k < results_block_config.length; k++) { // 重置 temp_block_ba_data this.resetTempBlockData(); const blockArr = results_block_config[k].block_arr; const date = this.temp_block_ba_data[i][j]; // 检测放置的方法 let config = this.getCenteredBlocks(date.index_i, date.index_j, blockArr); let isCanPlaced = config.iscanplaced; // 如果可以放置 if (isCanPlaced) { return false; } } } } // 移除道具检查逻辑 return true; } // 遍历检测每个块能否消除,并选择最优的三个块生成(生成特定选择块的方法) generateSpecificSelectionBlock(isPropFrash) { const results: { block: BlockConfig; totalEliminate: number }[] = []; for (let i = 0; i < this.block_ba_data.length; i++) { for (let j = 0; j < this.block_ba_data.length; j++) { for (let k = 0; k < BlocksAll.length; k++) { // 重置 temp_block_ba_data this.resetTempBlockData(); const blockArr = BlocksAll[k].block_arr; const date = this.temp_block_ba_data[i][j]; // 检测放置的方法 let config = this.getCenteredBlocks(date.index_i, date.index_j, blockArr); let isCanPlaced = config.iscanplaced; let placedIndexArr = config.indexarr; // 如果可以放置 if (isCanPlaced) { // 根据返回结果修改temp_block_ba_data对应位置的数据 for (let idx = 0; idx < placedIndexArr.length; idx++) { let boardindex_i = placedIndexArr[idx][0]; let boardindex_j = placedIndexArr[idx][1]; this.temp_block_ba_data[boardindex_i][boardindex_j].block_state = BlockState.SHOW; } // 返回消除的行列数 let totalEliminate = this.checkAndUpdateTempBlocks(); // 只有在 totalEliminate > 0 时才保存到 results if (totalEliminate > 0) { // 检查是否已经存在相同 block_type 的数据 const existingIndex = results.findIndex(result => result.block.block_type === BlocksAll[k].block_type); if (existingIndex !== -1) { // 如果存在且新的 totalEliminate 更大,则替换 if (results[existingIndex].totalEliminate < totalEliminate) { results[existingIndex] = { block: BlocksAll[k], totalEliminate }; } } else { // 如果不存在,则添加到 results results.push({ block: BlocksAll[k], totalEliminate }); } } } } } } // console.log(this.temp_block_ba_data); // console.log(this.block_ba_data); // 按 totalEliminate 排序,totalEliminate 最大的数据排在最前面 results.sort((a, b) => { if (b.totalEliminate !== a.totalEliminate) { return b.totalEliminate - a.totalEliminate; } else { // 如果 totalEliminate 相同,则按 block_arr 中 1 的数量排序,数量越少越排在前面 const countOnesA = this.countOnes(a.block.block_arr); const countOnesB = this.countOnes(b.block.block_arr); return countOnesA - countOnesB; } }); // console.log(results); let configs: BlockConfig[] = []; if (results.length >= 3) { for (let i = 0; i < 3; i++) { let colorIandU = mtec.number.random(0, 6, 0); switch (colorIandU) { case 0: results[i].block.block_color = Url.BLOCK.BLUE; break; case 1: results[i].block.block_color = Url.BLOCK.DEEPBLUE; break; case 2: results[i].block.block_color = Url.BLOCK.GREEN; break; case 3: results[i].block.block_color = Url.BLOCK.ORANGE; break; case 4: results[i].block.block_color = Url.BLOCK.PURPLE; break; case 5: results[i].block.block_color = Url.BLOCK.RED; break; case 6: results[i].block.block_color = Url.BLOCK.YELLOW; break; default: results[i].block.block_color = Url.BLOCK.BLUE; break; } configs.push(results[i].block) TouchMgr.ins.selectCanTouch[i] = true; } if (isPropFrash) { this.selects.forEach((block, index) => { tween(block) .to(0.2, { scale: v3(0, 0, 1) }) .call(() => { const blockConfig = configs[index]; block.setPosition(new Vec3(0, 0, 0)) block.getComponent(BlockController).updateBlockSet(true, blockConfig); block.getComponent(BlockController).addBlockOffset(4); block.active = true; }) .to(0.2, { scale: v3(0.5, 0.5, 1) }) .start() }) MainGameLogic.ins.propInUse = false; } else { this.SelectionContainer.setPosition(v3(view.getVisibleSize().width, 0, 0)) this.SelectionContainer.setScale(0, 0, 1); tween(this.SelectionContainer) .parallel( tween().to(0.5, { position: v3(0, 0, 0) }), tween().to(0.5, { scale: v3(1, 1, 1) }) ) .start() this.selects.forEach((block, index) => { const blockConfig = configs[index]; block.setPosition(new Vec3(0, 0, 0)) block.getComponent(BlockController).updateBlockSet(true, blockConfig); block.getComponent(BlockController).addBlockOffset(4); block.active = true }) } } else if (results.length == 2) { for (let i = 0; i < 2; i++) { let colorIandU = mtec.number.random(0, 6, 0); switch (colorIandU) { case 0: results[i].block.block_color = Url.BLOCK.BLUE; break; case 1: results[i].block.block_color = Url.BLOCK.DEEPBLUE; break; case 2: results[i].block.block_color = Url.BLOCK.GREEN; break; case 3: results[i].block.block_color = Url.BLOCK.ORANGE; break; case 4: results[i].block.block_color = Url.BLOCK.PURPLE; break; case 5: results[i].block.block_color = Url.BLOCK.RED; break; case 6: results[i].block.block_color = Url.BLOCK.YELLOW; break; default: results[i].block.block_color = Url.BLOCK.BLUE; break; } configs.push(results[i].block) TouchMgr.ins.selectCanTouch[i] = true; } configs.push(GridBlockMgr.ins.getRandomBlockConfig()) TouchMgr.ins.selectCanTouch[2] = true; if (isPropFrash) { this.selects.forEach((block, index) => { tween(block) .to(0.2, { scale: v3(0, 0, 1) }) .call(() => { const blockConfig = configs[index]; block.setPosition(new Vec3(0, 0, 0)) block.getComponent(BlockController).updateBlockSet(true, blockConfig); block.getComponent(BlockController).addBlockOffset(4); block.active = true }) .to(0.2, { scale: v3(0.5, 0.5, 1) }) .start() }) MainGameLogic.ins.propInUse = false; } else { this.SelectionContainer.setPosition(v3(view.getVisibleSize().width, 0, 0)); this.SelectionContainer.setScale(0, 0, 1); tween(this.SelectionContainer) .parallel( tween().to(0.5, { position: v3(0, 0, 0) }), tween().to(0.5, { scale: v3(1, 1, 1) }) ) .start() this.selects.forEach((block, index) => { const blockConfig = configs[index]; block.setPosition(new Vec3(0, 0, 0)) block.getComponent(BlockController).updateBlockSet(true, blockConfig); block.getComponent(BlockController).addBlockOffset(4); block.active = true }) } } else if (results.length == 1) { let colorIandU = mtec.number.random(0, 6, 0); switch (colorIandU) { case 0: results[0].block.block_color = Url.BLOCK.BLUE; break; case 1: results[0].block.block_color = Url.BLOCK.DEEPBLUE; break; case 2: results[0].block.block_color = Url.BLOCK.GREEN; break; case 3: results[0].block.block_color = Url.BLOCK.ORANGE; break; case 4: results[0].block.block_color = Url.BLOCK.PURPLE; break; case 5: results[0].block.block_color = Url.BLOCK.RED; break; case 6: results[0].block.block_color = Url.BLOCK.YELLOW; break; default: results[0].block.block_color = Url.BLOCK.BLUE; break; } configs.push(results[0].block) TouchMgr.ins.selectCanTouch[0] = true; for (let i = 1; i < 3; i++) { configs.push(GridBlockMgr.ins.getRandomBlockConfig()) TouchMgr.ins.selectCanTouch[i] = true; } if (isPropFrash) { this.selects.forEach((block, index) => { tween(block) .to(0.2, { scale: v3(0, 0, 1) }) .call(() => { const blockConfig = configs[index]; block.setPosition(new Vec3(0, 0, 0)) block.getComponent(BlockController).updateBlockSet(true, blockConfig); block.getComponent(BlockController).addBlockOffset(4); block.active = true }) .to(0.2, { scale: v3(0.5, 0.5, 1) }) .start() }) MainGameLogic.ins.propInUse = false; } else { this.SelectionContainer.setPosition(v3(view.getVisibleSize().width, 0, 0)) this.SelectionContainer.setScale(0, 0, 1); tween(this.SelectionContainer) .parallel( tween().to(0.5, { position: v3(0, 0, 0) }), tween().to(0.5, { scale: v3(1, 1, 1) }) ) .start() this.selects.forEach((block, index) => { const blockConfig = configs[index]; block.setPosition(new Vec3(0, 0, 0)) block.getComponent(BlockController).updateBlockSet(true, blockConfig); block.getComponent(BlockController).addBlockOffset(4); block.active = true }) } } else { this.generateSelectionBlock(isPropFrash) } this.detectSelectsBlockCanUse(true) } /** * 检测选择的三个块是否可以使用 * @param switchF */ detectSelectsBlockCanUse(switchF: boolean) { for (let i = 0; i < this.selects.length; i++) { const element = this.selects[i].getComponent(BlockController); if (switchF) { this.selects[i].parent.getChildByName('frash').active = false; } element.checkGray(); } } // 重置 temp_block_ba_data1 resetTempBlockData1() { for (let i = 0; i < this.block_ba_data.length; i++) { for (let j = 0; j < this.block_ba_data[i].length; j++) { this.temp_block_ba_data1[i][j] = { index_i: this.block_ba_data[i][j].index_i, index_j: this.block_ba_data[i][j].index_j, block_state: this.block_ba_data[i][j].block_state, block_ba_node: this.block_ba_data[i][j].block_ba_node, block_sprite: this.block_ba_data[i][j].block_ba_node.getComponent(ResSprite), block_color: this.block_ba_data[i][j].block_color }; } } } // 检测传入的块能否放置棋盘,不能则置灰 detectIsCanPlaced(block_arr: number[][], block_node: Node) { // 循环遍历results里的BlockConfig能不能放置 for (let i = 0; i < this.block_ba_data.length; i++) { for (let j = 0; j < this.block_ba_data[i].length; j++) { // 重置 temp_block_ba_data1 GridBlockMgr.ins.resetTempBlockData1(); const blockArr = block_arr const date = this.temp_block_ba_data1[i][j]; // 检测放置的方法 let config = this.getCenteredBlocks(date.index_i, date.index_j, blockArr); let isCanPlaced = config.iscanplaced; // 如果可以放置 if (isCanPlaced) { for (let i = 0; i < block_node.children.length; i++) { const element = block_node.children[i].getComponent(Sprite); element.grayscale = false; } return } else { for (let i = 0; i < block_node.children.length; i++) { const element = block_node.children[i].getComponent(Sprite); element.grayscale = true; } } } } } // 计算 block_arr 中 1 的数量的方法 countOnes(blockArr: number[][]): number { let count = 0; for (let i = 0; i < blockArr.length; i++) { for (let j = 0; j < blockArr[i].length; j++) { if (blockArr[i][j] === 1) { count++; } } } return count; } // 检测temp格子 消除方法 checkAndUpdateTempBlocks(): number { const size = this.temp_block_ba_data.length; let totalEliminated = 0; // 检查每一行 for (let i = 0; i < size; i++) { let rowAllOnes = true; for (let j = 0; j < size; j++) { if (this.temp_block_ba_data[i][j].block_state !== BlockState.SHOW) { rowAllOnes = false; break; } } if (rowAllOnes) { totalEliminated++; for (let j = 0; j < size; j++) { this.temp_block_ba_data[i][j].block_state = BlockState.HIDE; } } } // 检查每一列 for (let j = 0; j < size; j++) { let colAllOnes = true; for (let i = 0; i < size; i++) { if (this.temp_block_ba_data[i][j].block_state !== BlockState.SHOW) { colAllOnes = false; break; } } if (colAllOnes) { totalEliminated++; for (let i = 0; i < size; i++) { this.temp_block_ba_data[i][j].block_state = BlockState.HIDE; } } } return totalEliminated; } // 判断当前位置是否可以放置块 getCenteredBlocks(index_i: number, index_j: number, curBlockArr: number[][]): ReConfig { if (!curBlockArr) { return } const blocks: (number | null)[][] = Array(5).fill(null).map(() => Array(5).fill(null)); const blocks_ba_node: (Node | null)[][] = Array(5).fill(null).map(() => Array(5).fill(null)); const blocks_index: (number[] | null)[][] = Array(5).fill(null).map(() => Array(5).fill(null)); const startI = Math.max(index_i - 2, 0); const endI = Math.min(index_i + 2, this.temp_block_ba_data.length - 1); const startJ = Math.max(index_j - 2, 0); const endJ = Math.min(index_j + 2, this.temp_block_ba_data[0].length - 1); for (let i = startI; i <= endI; i++) { for (let j = startJ; j <= endJ; j++) { const block = this.temp_block_ba_data[i][j].block_state; const block_ba_node = this.temp_block_ba_data[i][j].block_ba_node; const block_index = [this.temp_block_ba_data[i][j].index_i, this.temp_block_ba_data[i][j].index_j]; blocks[i - (index_i - 2)][j - (index_j - 2)] = block; blocks_ba_node[i - (index_i - 2)][j - (index_j - 2)] = block_ba_node; blocks_index[i - (index_i - 2)][j - (index_j - 2)] = block_index } } for (let i = 0; i < 5; i++) { for (let j = 0; j < 5; j++) { const block = blocks[i][j]; const curBlock = curBlockArr[i][j]; if ((block === 1 && curBlock === 1) || (block === null && curBlock === 1)) { return { iscanplaced: false, indexarr: null }; } } } let returnIndexArr = []; // 显示提示位置 for (let i = 0; i < 5; i++) { for (let j = 0; j < 5; j++) { const block = blocks[i][j]; const curBlock = curBlockArr[i][j]; if ((block === 0 && curBlock === 1)) { // blocks_ba_node[i][j].getComponent(UIOpacity).opacity = 150; returnIndexArr.push(blocks_index[i][j]) } } } return { iscanplaced: true, indexarr: returnIndexArr }; } // 生成一个展示的临时图块 generateTempBlock(blockConfig: BlockConfig) { let tempblock = instantiate(this.block); tempblock.getComponent(BlockController).updateBlockSet(false, blockConfig); return tempblock; } }