| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592 |
- import { _decorator, Component, EventTouch, Material, Node, Sprite, UIOpacity, UITransform, v3, Vec2, Vec3 } from 'cc';
- import { AudioManager } from '../AudioManager';
- import { Url } from '../Url';
- import { BlockController } from './Block/BlockController';
- import { BlockConfig, BlocksAll, BlockState, ReConfig, Region } from './Block/BlockData';
- import GlobalData from './GlobalData';
- import { GridBlockMgr } from './GridBlockMgr';
- import { Guide } from './Guide';
- import { MainGameLogic } from './MainGameLogic';
- import ResSprite from '../ResSprite';
- const { ccclass, property } = _decorator;
- @ccclass('TouchMgr')
- export class TouchMgr extends Component {
- /** 单例模式 */
- private static _ins: TouchMgr;
- constructor() {
- super();
- TouchMgr._ins = this;
- }
- public static get ins(): TouchMgr {
- if (!TouchMgr._ins) {
- TouchMgr._ins = new TouchMgr();
- }
- return TouchMgr._ins;
- }
- @property(Node)
- selection_container: Node = null;
- //三个方块的选择区
- @property(Node)
- select1: Node = null;
- @property(Node)
- select2: Node = null;
- @property(Node)
- select3: Node = null;
- //三个方块的选择区的状态
- selectCanTouch: boolean[] = [false, false, false]
- @property(Node)
- tempBlock: Node = null; // 临时方块
- @property(Material)
- material: Material = null;
- @property(Material)
- defaultmaterial: Material = null;
- posOffset: Vec3 = new Vec3(0, 0, 0);
- isCanPlaced: boolean = false; // 是否可以放置
- // 是否可以放置的索引数组
- placedIndexArr: number[] = [];
- tempBlockColor: string = ''; // 临时方块的颜色
- private longPressThreshold: number = 200; // 长按阈值,单位毫秒
- private longPressTimerID: any = null;
- private isLongPress: boolean = false; // 是否长按
- vec3Reusable: Vec3 = new Vec3();
- private enlargedBlocks: Node[] = []; // 记录上一次放大的块
- private touchStartPos: Vec2;
- onLoad() {
- this.select1.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
- this.select1.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
- this.select1.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
- this.select1.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
- this.select2.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
- this.select2.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
- this.select2.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
- this.select2.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
- this.select3.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
- this.select3.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
- this.select3.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
- this.select3.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
- }
- start() {
- // log(this.selectCanTouch)
- // const p = this.getRegion(new Vec3(0, 300, 0));
- // console.log(GridBlockMgr.ins.block_ba_data[p.i][p.j].block_ba_node.position);
- // console.log(GridBlockMgr.ins.block_ba_data[p.i][p.j].index_i, GridBlockMgr.ins.block_ba_data[p.i][p.j].index_j);
- }
- //长按的数据
- private longPressEle: {
- event: EventTouch,
- touch_node: Node,
- target_block: Node,
- target_block_config: BlockConfig
- }
- onTouchStart(event: EventTouch) {
- AudioManager.ins.playOneShot(Url.AUDIO.SFX2, 1);
- this.isLongPress = false;
- this.resumePromptBlock();
- this.touchStartPos = event.getUILocation();
- let touch_node = event.getCurrentTarget() as Node;
- let touchSelectIndex = touch_node.getSiblingIndex();
- if (!this.selectCanTouch[touchSelectIndex]) {
- return;
- }
- // 获取点击的目标block
- let target_block = touch_node.children[0];
- // 获取block的BlockController组件中的BlockConfig数据
- let target_block_config: BlockConfig = target_block.getComponent(BlockController).curBlockConfig;
- this.tempBlockColor = target_block_config.block_color;
- this.longPressEle = {
- event,
- touch_node,
- target_block,
- target_block_config
- }
- // this.longPressTimerID = setTimeout(() => {
- // this.longPressFunc(this.longPressEle.event, this.longPressEle.touch_node, this.longPressEle.target_block, this.longPressEle.target_block_config);
- // }, this.longPressThreshold);
- }
- longPressFunc(event: EventTouch, touch_node: Node, target_block, target_block_config) {
- this.isLongPress = true;
- touch_node.children[1].active = false;
- // 点击之后下方展示block隐藏
- target_block.active = false;
- // 生成一个要跟随鼠标移动的临时block,并将位置放在鼠标点击位置
- this.tempBlock.active = true;
- this.tempBlock.getComponent(BlockController).updateBlockSet(false, target_block_config);
- const touch_pos = event.getUILocation();
- const temp_touch_pos = this.getRelativePosition(this.selection_container, this.vec2ToVec3(touch_pos));
- // 设置临时block的位置到点击位置
- this.tempBlock.setPosition(temp_touch_pos.add(new Vec3(0, 250, 0))); // 将tempBlock位置放在点击位置的上方200处
- this.tempBlock.getComponent(BlockController).addBlockOffset(2);
- // 获取临时tempBlock和鼠标之间的向量差
- // this.posOffset = this.vectorDifference(temp_touch_pos, this.tempBlock.position);
- }
- calculateDistance(vec1: Vec2, vec2: Vec2): number {
- return Vec2.distance(vec1, vec2);
- }
- onTouchMove(event: EventTouch) {
- // clearTimeout(this.longPressTimerID);
- let touchMovePos = event.getUILocation();
- // console.log(this.calculateDistance(touchMovePos, this.touchStartPos));
- if (this.calculateDistance(touchMovePos, this.touchStartPos) <= 25) {
- //太短就不管
- return
- }
- // console.log("MOVE");
- this.longPressFunc(this.longPressEle.event, this.longPressEle.touch_node, this.longPressEle.target_block, this.longPressEle.target_block_config)
- this.resumePromptBlock();
- let touch_node = event.getCurrentTarget() as Node;
- let touchSelectIndex = touch_node.getSiblingIndex();
- if (!this.selectCanTouch[touchSelectIndex]) {
- return;
- }
- touch_node.children[1].active = false;
- // 获取鼠标当前位置并转换
- let touch_pos = event.getUILocation();
- // let temp_touch_pos = this.getRelativePosition(this.selection_container, this.vec2ToVec3(touch_pos));
- const temp_touch_pos = this.getRelativePosition(this.selection_container, this.vec2ToVec3(touch_pos));
- // 设置临时block的位置到点击位置
- this.tempBlock.setPosition(temp_touch_pos.add(new Vec3(0, 250, 0))); // 将tempBlock位置放在点击位置的上方200处
- this.tempBlock.getComponent(BlockController).addBlockOffset(2);
- let pos_to_grid = this.getNodeAToNodeBPoint(GridBlockMgr.ins.gridcontainer.parent, this.tempBlock);
- let indexi_j = this.getRegion(new Vec3(pos_to_grid.x, pos_to_grid.y, 0));
- GridBlockMgr.ins.updateBoard();
- if (indexi_j) {
- let date = GridBlockMgr.ins.block_ba_data[indexi_j.i][indexi_j.j];
- let tempBlockData = this.tempBlock.getComponent(BlockController).curBlockConfig;
- if (!tempBlockData) {
- return;
- }
- let config = this.getCenteredBlocks(date.index_i, date.index_j, tempBlockData.block_arr, tempBlockData.block_color, this.tempBlock);
- // console.log(config);
- this.isCanPlaced = config.iscanplaced;
- this.placedIndexArr = config.indexarr;
- this.tempBlockColor = tempBlockData.block_color;
- } else {
- this.isCanPlaced = false;
- }
- }
- onTouchEnd(event: EventTouch) {
- this.resumePromptBlock();
- let touch_node = event.getCurrentTarget() as Node;
- let touchSelectIndex = touch_node.getSiblingIndex();
- if (!this.selectCanTouch[touchSelectIndex]) {
- return;
- }
- // if (this.longPressTimerID) {
- // clearTimeout(this.longPressTimerID);
- // this.longPressTimerID = null;
- // }
- if (this.isLongPress) {
- touch_node.children[1].active = false;
- GridBlockMgr.ins.updateBoard();
- if (this.isCanPlaced) {
- //可以放置
- AudioManager.ins.playOneShot(Url.AUDIO.SFX3, 1);
- this.tempBlock.active = false;
- for (let i = 0; i < this.placedIndexArr.length; i++) {
- //这做一个吸附效果,从上到下,快点放置上去,而不是全部一起直接放置,很生硬
- let boardindex_i = this.placedIndexArr[i][0];
- let boardindex_j = this.placedIndexArr[i][1];
- GridBlockMgr.ins.block_ba_data[boardindex_i][boardindex_j].block_state = BlockState.SHOW;
- GridBlockMgr.ins.block_ba_data[boardindex_i][boardindex_j].block_ba_node.getComponent(UIOpacity).opacity = 255;
- GridBlockMgr.ins.block_ba_data[boardindex_i][boardindex_j].block_sprite.setSpriteFrame(this.tempBlockColor + '/spriteFrame');
- GridBlockMgr.ins.block_ba_data[boardindex_i][boardindex_j].block_color = this.tempBlockColor;
- // node.getComponent(ResSprite).setSpriteFrame(blockConfig.block_color + '/spriteFrame');
- }
- this.selectCanTouch[touch_node.getSiblingIndex()] = false;
- let is_empty = this.selectionConEmpty();
- if (is_empty && GlobalData.guideRecord > 3) {
- // GridBlockMgr.ins.generateSpecificSelectionBlock(false);
- GridBlockMgr.ins.generateSelectionBlock(false);
- }
- GridBlockMgr.ins.checkAndUpdateBlocks();
- } else {
- //不可以放置
- let targetBlock = touch_node.children[0];
- targetBlock.active = true;
- this.tempBlock.active = false;
- }
- this.isCanPlaced = false;
- if (!GlobalData.isCommer) {
- let isOver = GridBlockMgr.ins.detectGameOver();
- // console.log(isOver);
- if (isOver) {
- MainGameLogic.ins.gameOver();
- }
- }
- this.isLongPress = false;
- } else {
- //旋转逻辑
- if (!GlobalData.isRotate) {
- return
- }
- let target_block_config = touch_node.children[0].getComponent(BlockController).curBlockConfig;
- if (target_block_config.block_type != 0 && target_block_config.block_type != 4 && target_block_config.block_type != 5) {
- touch_node.children[1].active = true;
- }
- let new_target_block_arr = this.rotateMatrix(target_block_config.block_arr);
- const matchingBlockConfig = this.findMatchingBlockConfig(new_target_block_arr);
- matchingBlockConfig.block_color = this.tempBlockColor;
- touch_node.children[0].getComponent(BlockController).updateBlockSet(true, matchingBlockConfig);
- touch_node.children[0].setPosition(Vec3.ZERO);
- touch_node.children[0].getComponent(BlockController).addBlockOffset(4);
- if (!GlobalData.isCommer) {
- let isOver = GridBlockMgr.ins.detectGameOver();
- if (isOver) {
- MainGameLogic.ins.gameOver();
- }
- }
- }
- GridBlockMgr.ins.detectSelectsBlockCanUse(false);
- }
- // 判断数组一致性
- arraysEqual(arr1: number[][], arr2: number[][]): boolean {
- if (arr1.length !== arr2.length) return false;
- for (let i = 0; i < arr1.length; i++) {
- if (arr1[i].length !== arr2[i].length) return false;
- for (let j = 0; j < arr1[i].length; j++) {
- if (arr1[i][j] !== arr2[i][j]) return false;
- }
- }
- return true;
- }
- // 根据旋转后的二维数组,找到匹配的数据
- public findMatchingBlockConfig(arr: number[][]): BlockConfig | null {
- for (const block of BlocksAll) {
- if (this.arraysEqual(block.block_arr, arr)) {
- return block;
- }
- }
- return null;
- }
- //获取地区
- getRegion(pos: Vec3): Region | null {
- const nodeSize = 980; // 节点的大小
- const gridSize = 8; // 区域的数量
- const cellSize = 122.5; // 每个区域块的大小
- // 中心点的偏移量
- const halfNodeSize = nodeSize / 2;
- // 转换坐标到以中心点为原点的坐标系
- const localX = pos.x + halfNodeSize;
- const localY = pos.y + halfNodeSize;
- // 计算坐标所在的区域块索引
- const i = Math.floor((localY) / cellSize);
- const j = gridSize - 1 - Math.floor(localX / cellSize);
- // 检查索引是否在有效范围内
- if (i >= 0 && i < gridSize && j >= 0 && j < gridSize) {
- return { i, j };
- } else {
- return null;
- }
- }
- // 获取中心块的坐标和颜色
- // index_i: 当前块的行索引
- getCenteredBlocks(index_i: number, index_j: number, curBlockArr: number[][], curBlockColor: string, tempBlock: Node): ReConfig {
- if (!curBlockArr) {
- this.resumePromptBlock();
- return { iscanplaced: false, indexarr: null };
- }
- // 检查是否处于引导状态,并验证当前位置是否符合引导位置
- if (GlobalData.isCommer) {
- this.resumePromptBlock();
- if ((GlobalData.guideRecord == 1 && (index_i != Guide.ins.guideindex1[0] || index_j != Guide.ins.guideindex1[1])) ||
- (GlobalData.guideRecord == 2 && (index_i != Guide.ins.guideindex2[0] || index_j != Guide.ins.guideindex2[1])) ||
- (GlobalData.guideRecord == 3 && (index_i != Guide.ins.guideindex3[0] || index_j != Guide.ins.guideindex3[1]))) {
- return { iscanplaced: false, indexarr: null };
- }
- }
- 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, GridBlockMgr.ins.block_ba_data.length - 1);
- const startJ = Math.max(index_j - 2, 0);
- const endJ = Math.min(index_j + 2, GridBlockMgr.ins.block_ba_data[0].length - 1);
- for (let i = startI; i <= endI; i++) {
- for (let j = startJ; j <= endJ; j++) {
- const block = GridBlockMgr.ins.block_ba_data[i][j].block_state;
- const block_ba_node = GridBlockMgr.ins.block_ba_data[i][j].block_ba_node;
- const block_index = [GridBlockMgr.ins.block_ba_data[i][j].index_i, GridBlockMgr.ins.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)) {
- this.resumePromptBlock();
- 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;
- blocks_ba_node[i][j].getComponent(ResSprite).setSpriteFrame(curBlockColor + '/spriteFrame')
- returnIndexArr.push(blocks_index[i][j]);
- }
- }
- }
- // 处理 tempBlock 的 25 个子节点并建立映射关系
- const tempBlockChildren = tempBlock.children;
- const tempBlockArr: (Node | null)[][] = Array(5).fill(null).map(() => Array(5).fill(null));
- for (let i = 0; i < 5; i++) {
- for (let j = 0; j < 5; j++) {
- tempBlockArr[i][j] = tempBlockChildren[i * 5 + j];
- }
- }
- // 创建临时棋盘数据对象,并模拟 tempBlock 已经放置
- const tempGrid = Array(8).fill(null).map(() => Array(8).fill(0));
- for (let i = 0; i < 8; i++) {
- for (let j = 0; j < 8; j++) {
- tempGrid[i][j] = GridBlockMgr.ins.block_ba_data[i][j].block_state;
- }
- }
- // 模拟放置 curBlockArr 到临时棋盘上
- for (let i = 0; i < 5; i++) {
- for (let j = 0; j < 5; j++) {
- if (curBlockArr[i][j] === 1) {
- const gridI = index_i - 2 + i;
- const gridJ = index_j - 2 + j;
- if (gridI >= 0 && gridI < 8 && gridJ >= 0 && gridJ < 8) {
- tempGrid[gridI][gridJ] = 1;
- }
- }
- }
- }
- // 检查临时棋盘是否有可消除的行或列
- let canEliminate = false;
- const rowsToCheck = [];
- const colsToCheck = [];
- for (let i = 0; i < 8; i++) {
- if (tempGrid[i].every(value => value === 1)) {
- canEliminate = true;
- rowsToCheck.push(i);
- }
- if (tempGrid.every(row => row[i] === 1)) {
- canEliminate = true;
- colsToCheck.push(i);
- }
- }
- if (canEliminate) {
- // 放大真实棋盘上可消除的块
- rowsToCheck.forEach(row => {
- for (let j = 0; j < 8; j++) {
- const blockNode = GridBlockMgr.ins.block_ba_data[row][j].block_ba_node;
- if (blockNode && GridBlockMgr.ins.block_ba_data[row][j].block_state === BlockState.SHOW) {
- blockNode.getComponent(Sprite).material = this.material;
- this.enlargedBlocks.push(blockNode); // 记录放大的块
- }
- }
- });
- 5
- colsToCheck.forEach(col => {
- for (let i = 0; i < 8; i++) {
- const blockNode = GridBlockMgr.ins.block_ba_data[i][col].block_ba_node;
- if (blockNode && GridBlockMgr.ins.block_ba_data[i][col].block_state === BlockState.SHOW) {
- blockNode.getComponent(Sprite).material = this.material;
- this.enlargedBlocks.push(blockNode); // 记录放大的块
- }
- }
- });
- // 放大 tempBlock 中会产生消除的块
- for (let i = 0; i < 5; i++) {
- for (let j = 0; j < 5; j++) {
- if (curBlockArr[i][j] === 1) {
- const gridI = index_i - 2 + i;
- const gridJ = index_j - 2 + j;
- if (rowsToCheck.includes(gridI) || colsToCheck.includes(gridJ)) {
- tempBlockArr[i][j].getComponent(Sprite).material = this.material;
- this.enlargedBlocks.push(tempBlockArr[i][j]); // 记录放大的块
- }
- }
- }
- }
- } else {
- this.resumePromptBlock();
- }
- return { iscanplaced: true, indexarr: returnIndexArr };
- }
- resumePromptBlock() {
- // 恢复上一次放大的块大小
- this.enlargedBlocks.forEach(node => {
- node.getComponent(Sprite).material = this.defaultmaterial;
- });
- this.enlargedBlocks = []; // 清空放大块的记录
- }
- /**
- * 获取坐标在目标节点(容器)下的相对位置
- * @param container 目标节点(容器)
- * @param nodepos 已有node节点坐标可传
- */
- public getRelativePosition(container: Node, nodepos?: Vec3,): Vec3 {
- //const worldPos = (node.getParent() || node).getComponent(UITransform).convertToWorldSpaceAR(nodepos ? nodepos : node.getPosition());
- return container.getComponent(UITransform).convertToNodeSpaceAR(nodepos);
- }
- /**
- * 获取A相对B的局部坐标
- * @param {*} nodeA
- * @param {*} nodeB
- */
- public getNodeAToNodeBPoint(nodeA: Node, nodeB: Node) {
- var nodeAWorldPoint = nodeA.getComponent(UITransform).convertToWorldSpaceAR(Vec3.ZERO);
- //console.log("nodeAWorldPoint",nodeAWorldPoint);
- var AToBPos = nodeB.getComponent(UITransform).convertToNodeSpaceAR(nodeAWorldPoint);
- return v3(AToBPos.x, AToBPos.y, 1) //{ x: AToBPos.x, y: AToBPos.y };
- }
- /**
- * 计算两个向量的差
- * @param vec1 向量1
- * @param vec2 向量2
- * @returns
- */
- vectorDifference(vec1: Vec3, vec2: Vec3): Vec3 {
- // 使用 cc.Vec3 的 subtract 方法计算向量差
- const result = new Vec3();
- Vec3.subtract(result, vec1, vec2);
- return result;
- }
- /**
- *
- * @param arr 判断选择区是否已经清空
- * @returns
- */
- selectionConEmpty(): boolean {
- for (let i = 0; i < this.selectCanTouch.length; i++) {
- if (this.selectCanTouch[i] !== false) {
- return false;
- }
- }
- return true;
- }
- /**
- * 二维数组旋转
- * @param matrix 二维矩阵
- * @param clockwise 是否顺时针
- * @returns
- */
- rotateMatrix(matrix: any[][], clockwise: boolean = true): any[][] {
- const N = matrix.length;
- const rotatedMatrix: any[][] = [];
- for (let i = 0; i < N; i++) {
- rotatedMatrix.push([]);
- }
- for (let i = 0; i < N; i++) {
- for (let j = 0; j < N; j++) {
- if (clockwise) {
- rotatedMatrix[j][N - 1 - i] = matrix[i][j];
- } else {
- rotatedMatrix[N - 1 - j][i] = matrix[i][j];
- }
- }
- }
- return rotatedMatrix;
- }
- /**
- * Vec2转Vec3
- * @param vec2 一个Vec2
- * @returns 一个Vec3
- */
- vec2ToVec3(vec2: Vec2): Vec3 {
- this.vec3Reusable.set(vec2.x, vec2.y, 0);
- return this.vec3Reusable;
- }
- }
|