import { _decorator, Component, Node, PhysicsSystem, Camera, EventTouch, find, geometry, Layers, Vec3, Vec2, quat, DirectionalLight, Quat, AudioSource, AudioClip } from 'cc'; import { CreateMap } from './CreateMap'; import { CubeInfo } from './CubeInfo'; import { UpdateLayer } from './UpdateLayer'; import { UpdateScore } from './UpdateScore'; import { ShowTip } from './ShowTip'; import { EasyColorStrategy, HardColorStrategy, NormalColorStrategy, StrategyManager } from './StrategyManager'; import { GameState, PlayState, StateManager } from './StateManager'; import { UIManager } from '../UIFrameWork/UIManager'; import { LoadRes } from '../Config/LoadRes'; import ch_audio from '../../ch/audio/audio'; const { ccclass, property } = _decorator; @ccclass('PlayerCtl') export class PlayerCtl extends Component { public static instance: PlayerCtl = null; private cameraNode: Node = null; @property(Camera) private camera: Camera | null = null; private light: Node = null; private dir: number[][] = [[0, 0, 1], [0, 1, 0], [0, 0, -1], [0, -1, 0]]; private waitDestroy: Vec3[] = [];//等待销毁的所有节点 public layerIndex: number = 1;//已开启层数 private surfaceLayer: number = 1;//表层 private needMoveLayer: number = 0;// private totalDestroy: number = 0; private startTouchPos: Vec2 = null; private moveDistance: number = 0; private swipeThreshold: number = 50; // 滑动阈值 public touchLock: boolean = true;//触摸锁定状态 onLoad() { PlayerCtl.instance = this; // 获取场景中的主光源 this.light = find('Main Light'); // 获取场景中的主摄像头 this.cameraNode = find('Main Camera'); if (this.cameraNode) { this.camera = this.cameraNode.getComponent(Camera); } // 监听触摸开始事件 this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this); this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this); this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this); } onTouchStart(event: EventTouch) { // 确保获取的是第一个触摸点 if (!this.touchLock&&StateManager.getInstance().getState() instanceof PlayState) { this.startTouchPos = event.getLocation(); } } //滑动屏幕让当前层类似于2048游戏中的上下左右移动,并不合并/消除 onTouchMove(event: EventTouch) { const currentTouchPos = event.getLocation(); if (this.startTouchPos&&StateManager.getInstance().getState() instanceof PlayState) { const moveVector = new Vec2(currentTouchPos.x - this.startTouchPos.x, currentTouchPos.y - this.startTouchPos.y); this.moveDistance = moveVector.length(); // 更新滑动距离 console.log("触摸屏幕"); } } onTouchEnd(event: EventTouch) { if (!this.startTouchPos || this.touchLock || !(StateManager.getInstance().getState() instanceof PlayState)) return; //移动动画在执行时应关闭触摸判断 const currentTouchPos = event.getLocation(); const moveVector = new Vec2(currentTouchPos.x - this.startTouchPos.x, currentTouchPos.y - this.startTouchPos.y); if (this.moveDistance > this.swipeThreshold) { const direction = moveVector.normalize(); // 返回方向向量 this.handleSwipe(direction); // 处理滑动 } else { this.shootRay(event); } this.startTouchPos = null; // 重置触摸位置 this.moveDistance = 0; // 重置滑动距离 } handleSwipe(direction: Vec2) { // 确定滑动方向对应的索引 let directionIndex = -1; const horizontalThreshold = 0.7; const verticalThreshold = 0.7; if (Math.abs(direction.x) > horizontalThreshold && Math.abs(direction.y) < verticalThreshold) { // 主要是水平方向移动 if (direction.x < 0) { directionIndex = 3; // 向左 } else if (direction.x > 0) { directionIndex = 1; // 向右 // this.light.setRotationFromEuler(new Vec3(10, 0, 0)); } } else if (Math.abs(direction.y) > verticalThreshold && Math.abs(direction.x) < horizontalThreshold) { // 主要是垂直方向移动 if (direction.y < 0) directionIndex = 2; // 向下 else if (direction.y > 0) directionIndex = 0; // 向上 } if (directionIndex !== -1) { this.moveLayer(directionIndex); } } //已解锁的层都需要移动 // moveLayer(directionIndex) { // this.touchLock = true; // let map = CreateMap.getInstance().GetMap(); // let maxKIJ = CreateMap.getInstance().GetMaxKIJ(); // for (let k = this.surfaceLayer - 1; k < this.layerIndex; k++) { // // 创建一个临时数组来存储移动后的方块状态 // let tempMap = new Array(maxKIJ.y).fill(null).map(() => new Array(maxKIJ.z).fill(null)); // // 左右移动 // if (directionIndex === 3 || directionIndex === 1) { // for (let i = 0; i < maxKIJ.y; i++) { // let newRow = []; // for (let j = 0; j < maxKIJ.z; j++) { // let cube = map[k][i][j]; // if (cube) { // newRow.push({ cube }); // } // } // // 向左移动 // if (directionIndex === 3) { // for (let j = 0; j < maxKIJ.z; j++) { // let item = newRow.shift(); // 取出最左边的方块 // if (item) { // tempMap[i][j] = item.cube; // item.cube.getComponent(CubeInfo).setPos(k, i, j); // } // } // } // // 向右移动 // else { // for (let j = maxKIJ.z - 1; j >= 0; j--) { // let item = newRow.pop(); // 取出最右边的方块 // if (item) { // tempMap[i][j] = item.cube; // item.cube.getComponent(CubeInfo).setPos(k, i, j); // } // } // } // } // } // // 上下移动 // else if (directionIndex === 0 || directionIndex === 2) { // for (let j = 0; j < maxKIJ.z; j++) { // let newCol = []; // for (let i = 0; i < maxKIJ.y; i++) { // let cube = map[k][i][j]; // if (cube) { // newCol.push({ cube }); // } // } // // 向上移动 // if (directionIndex === 0) { // for (let i = 0; i < maxKIJ.y; i++) { // let item = newCol.shift(); // 取出最下面的方块 // if (item) { // tempMap[i][j] = item.cube; // item.cube.getComponent(CubeInfo).setPos(k, i, j); // } // } // } // // 向下移动 // else { // for (let i = maxKIJ.y - 1; i >= 0; i--) { // let item = newCol.pop(); // 取出最上面的方块 // if (item) { // tempMap[i][j] = item.cube; // item.cube.getComponent(CubeInfo).setPos(k, i, j); // } // } // } // } // } // // // 更新地图数据 // CreateMap.getInstance().setMap(tempMap, k, this.needMoveLayer); // } // //更新颜色 // CreateMap.getInstance().changeColor(this.surfaceLayer-1,this.layerIndex); // } moveLayer(directionIndex) { this.touchLock = true; let map = CreateMap.getInstance().GetMap(); let maxKIJ = CreateMap.getInstance().GetMaxKIJ(); for (let k = this.surfaceLayer - 1; k < this.layerIndex; k++) { let tempMap = new Array(maxKIJ.y).fill(null).map(() => new Array(maxKIJ.z).fill(null)); // 左右移动 if (directionIndex === 3 || directionIndex === 1) { for (let i = 0; i < maxKIJ.y; i++) { let newRow = []; for (let j = 0; j < maxKIJ.z; j++) { let cube = map[k][i][j]; if (cube) { newRow.push({ cube }); } } // 向左移动 if (directionIndex === 3) { for (let j = 0; j < maxKIJ.z; j++) { let item = newRow.shift(); // 取出最左边的方块 if (item) { tempMap[i][j] = item.cube; item.cube.getComponent(CubeInfo).setPos(k, i, j); } } } // 向右移动 else { for (let j = maxKIJ.z - 1; j >= 0; j--) { let item = newRow.pop(); // 取出最右边的方块 if (item) { tempMap[i][j] = item.cube; item.cube.getComponent(CubeInfo).setPos(k, i, j); } } } } } // 上下移动 else if (directionIndex === 0 || directionIndex === 2) { for (let j = 0; j < maxKIJ.z; j++) { let newCol = []; for (let i = 0; i < maxKIJ.y; i++) { let cube = map[k][i][j]; if (cube) { newCol.push({ cube }); } } // 向上移动 if (directionIndex === 0) { for (let i = 0; i < maxKIJ.y; i++) { let item = newCol.shift(); // 取出最下面的方块 if (item) { tempMap[i][j] = item.cube; item.cube.getComponent(CubeInfo).setPos(k, i, j); } } } // 向下移动 else { for (let i = maxKIJ.y - 1; i >= 0; i--) { let item = newCol.pop(); // 取出最上面的方块 if (item) { tempMap[i][j] = item.cube; item.cube.getComponent(CubeInfo).setPos(k, i, j); } } } } } CreateMap.getInstance().setMap(tempMap, k, this.needMoveLayer); } CreateMap.getInstance().changeColor(this.surfaceLayer - 1, this.layerIndex); } //发射射线检测判断物体是否可消除 shootRay(event: EventTouch) { if (!this.camera) return; let ray = new geometry.Ray(); this.camera.screenPointToRay(event.getLocationX(), event.getLocationY(), ray); const index = Layers.nameToLayer('Cube'); const mask = 1 << index; const maxDistance = 10000000; const queryTrigger = true; if (PhysicsSystem.instance.raycastClosest(ray, mask, maxDistance, queryTrigger)) { const raycastClosestResult = PhysicsSystem.instance.raycastClosestResult; const hitPoint = raycastClosestResult.hitPoint; const hitNormal = raycastClosestResult.hitNormal; const collider = raycastClosestResult.collider; const distance = raycastClosestResult.distance; console.log(collider.node.name); //检测周边四个方向相同颜色的物体 this.checkNearCube(collider.node.getComponent(CubeInfo).getPos()); //拿取到所有连续颜色相同的物体,进行销毁 this.destroyCollectedCubes(); //最多允许同时存在3层,如果当前有三层未销毁完,但已开启第四层,消除最上层所有元素且不计分 this.judgeSurface();//得出表层 if (this.calcDifference())//超出三层 { console.log("相差层数大于3层"); //弹出广告界面,不看广告游戏结束 UIManager.Instance.ShowUI("ad", LoadRes.getInstance().adPanel); } } console.log('发射了射线'); } //多层堆叠的map,但是要从2d视角检测当前方块四方向是否有连续同色,采用BFS checkNearCube(Pos: Vec3) { console.log(Pos); let map = CreateMap.getInstance().GetMap(); let maxKIJ = CreateMap.getInstance().GetMaxKIJ(); let currentCubeInfo = map[Pos.x][Pos.y][Pos.z]?.getComponent(CubeInfo); if (!currentCubeInfo || Pos.x >= this.layerIndex) return; let cubeId = currentCubeInfo.getId(); let count = 0; let toMarkAsNull: Vec3[] = []; let queue: Vec3[] = []; queue.push(Pos); let visited: boolean[][][] = new Array(maxKIJ.x).fill(false).map(() => new Array(maxKIJ.y).fill(false).map(() => new Array(maxKIJ.z).fill(false))); while (queue.length > 0) { let currentPos = queue.shift(); if (!currentPos) continue; let x = currentPos.x; let y = currentPos.y; let z = currentPos.z; // 检查边界条件和是否已经访问过 if (x < 0 || x >= maxKIJ.x || y < 0 || y >= maxKIJ.y || z < 0 || z >= maxKIJ.z || visited[x][y][z]) continue; let cubeInfo = map[x][y][z]?.getComponent(CubeInfo); if (cubeInfo && cubeInfo.getId() === cubeId) { count++; toMarkAsNull.push(new Vec3(x, y, z)); this.dir.forEach(d => { let newX = x + d[0]; let newY = y + d[1]; let newZ = z + d[2]; // 确保新的坐标在边界内,并且目标块不为空,并且是已解锁 if (newX >= 0 && newX < maxKIJ.x && newY >= 0 && newY < maxKIJ.y && newZ >= 0 && newZ < maxKIJ.z && !visited[newX][newY][newZ] && map[newX][newY][newZ] && !map[newX][newY][newZ].getComponent(CubeInfo).getLock()) { queue.push(new Vec3(newX, newY, newZ)); } //旁边无方块 else { //判断更深层次 for (let i = 1; i < 4; i++) { if (newX + i >= 0 && newX + i < maxKIJ.x && newY >= 0 && newY < maxKIJ.y && newZ >= 0 && newZ < maxKIJ.z && !visited[newX + i][newY][newZ] && map[newX + i][newY][newZ] && !map[newX + i][newY][newZ].getComponent(CubeInfo).getLock()) { queue.push(new Vec3(newX + i, newY, newZ)); } } //判断更浅层次 for (let i = 1; i < 4; i++) { if (newX - i >= 0 && newX - i < maxKIJ.x && newY >= 0 && newY < maxKIJ.y && newZ >= 0 && newZ < maxKIJ.z && !visited[newX - i][newY][newZ] && map[newX - i][newY][newZ] && !map[newX - i][newY][newZ].getComponent(CubeInfo).getLock()) { queue.push(new Vec3(newX - i, newY, newZ)); } } } }); visited[x][y][z] = true; } } //连续颜色相同方块大于等于三个时,将每个方块放入待销毁数组 if (count >= 3) { toMarkAsNull.forEach(pos => { this.waitDestroy.push(new Vec3(pos.x, pos.y, pos.z)); }); } // else { // // 如果数量小于 3,确保不进行错误操作 // toMarkAsNull.forEach(pos => { // // 检查 map 中对应位置是否为 null,如果为 null 则不进行任何操作 // if (map[pos.x] && map[pos.x][pos.y] && map[pos.x][pos.y][pos.z]) { // if (!this.waitDestroy.some(item => item === map[pos.x][pos.y][pos.z])) { // // 保持方块状态不变 // } // } // }); // } } //销毁方块 destroyCollectedCubes() { let map = CreateMap.getInstance().GetMap(); if (this.waitDestroy.length >= 3) { if(ch_audio.getInstance().volumeEffect) { ch_audio.getInstance().playOneShot('Break'); } this.waitDestroy.forEach(cube => { if (cube) { //调用爆炸特效 // map[cube.x][cube.y][cube.z].getComponent(CubeInfo).triggerDissolve(); CreateMap.getInstance().destroyNode(cube); if (cube.x + 1 === this.layerIndex) { this.totalDestroy++; console.log('当前层销毁了' + this.totalDestroy + '个'); } // this.score += 10; // 假设每销毁一个块加10分 } }); this.calculateScore(this.waitDestroy.length); } this.waitDestroy = []; // 清空等待销毁的块列表 let maxKIJ = CreateMap.getInstance().GetMaxKIJ(); if (this.totalDestroy / (maxKIJ.y * maxKIJ.z) > 0.8)//消除表层80%,解锁下层 { this.layerIndex++; UpdateLayer.instance.Update_Layer(this.layerIndex); this.totalDestroy = 0; console.log("调用新增实例层"); } //如果表层被玩家自己消除完了,下面所有层都需要上移 if (this.CalcSurface()) { CreateMap.getInstance().initNewLayer(maxKIJ.x, this.needMoveLayer); this.needMoveLayer++;//需移动的层数+1 let maxK = CreateMap.getInstance().GetMaxKIJ().x; for (let k = this.surfaceLayer - 1; k < maxK; k++) { CreateMap.getInstance().setMap(map[k], k, this.needMoveLayer); } } //更新颜色 CreateMap.getInstance().changeColor(this.surfaceLayer - 1, this.layerIndex); } //加分 calculateScore(length: number) { let score = 0; //销毁后进行加分,3-5个为基础分每个方块5分,6-8个每个方块多算10分,9-15个每个方块多算20分,16个以上每个方块多算50分 if (length >= 3 && length <= 5) { ShowTip.instance.Show_Tip('Good'); score = length * 5; } else if (length >= 6 && length <= 8) { ShowTip.instance.Show_Tip('Great'); score = length * 15; } else if (length >= 9 && length <= 15) { ShowTip.instance.Show_Tip('Unbeliveable'); score = length * 25; } else if (length >= 16) { ShowTip.instance.Show_Tip('excellent'); score = length * 55; } UpdateScore.instance.Update_Score(score); } //判断哪一层是表层 judgeSurface() { let maxKIJ = CreateMap.getInstance().GetMaxKIJ(); let map = CreateMap.getInstance().GetMap(); for (let k = 0; k < this.layerIndex; k++) { for (let i = 0; i < maxKIJ.y; i++) { for (let j = 0; j < maxKIJ.z; j++) { if (map[k][i][j] !== null) { this.surfaceLayer = k + 1;//更新表层 console.log("表层是" + this.surfaceLayer); return; } } } } } CalcSurface(): boolean { let maxKIJ = CreateMap.getInstance().GetMaxKIJ(); let map = CreateMap.getInstance().GetMap(); for (let i = 0; i < maxKIJ.y; i++) { for (let j = 0; j < maxKIJ.z; j++) { if (map[this.surfaceLayer - 1][i][j] !== null) { //表层没被消除完 return false; } } } CreateMap.getInstance().setMap(map[this.surfaceLayer - 1], this.surfaceLayer - 1, this.needMoveLayer); this.surfaceLayer++;//更新表层 return true; } //计算深度差 calcDifference(): boolean { return (this.layerIndex - (this.surfaceLayer - 1)) > 1 ? true : false; } //弹出广告界面,销毁表层方块 destroySurfaceCube(index: number) { let maxKIJ = CreateMap.getInstance().GetMaxKIJ(); let map = CreateMap.getInstance().GetMap(); for (let i = 0; i < maxKIJ.y; i++) { for (let j = 0; j < maxKIJ.z; j++) { if (map[index][i][j] !== null) { console.log("应该销毁第" + index + "层"); //调用爆炸特效 CreateMap.getInstance().destroyNode(new Vec3(index, i, j)); } } } this.surfaceLayer++;//更新表层 CreateMap.getInstance().initNewLayer(maxKIJ.x, this.needMoveLayer); this.needMoveLayer++; } //看了广告要执行的内容 public onAdFinish() { //销毁表层 this.destroySurfaceCube(this.surfaceLayer - 1); //下层所有层向上移动一层 let maxKIJ = CreateMap.getInstance().GetMaxKIJ(); let map = CreateMap.getInstance().GetMap(); for (let k = this.surfaceLayer - 1; k < maxKIJ.x; k++) { CreateMap.getInstance().setMap(map[k], k, this.needMoveLayer); } } }