import { _decorator, Component, Node, PhysicsSystem, Camera, EventTouch, find, geometry, Layers, Vec3, Vec2 } from 'cc'; import { CreateMap } from './CreateMap'; import { CubeInfo } from './CubeInfo'; import { UpdateLayer } from './UpdateLayer'; import { UpdateScore } from './UpdateScore'; import { ShowTip } from './ShowTip'; const { ccclass, property } = _decorator; @ccclass('PlayerCtl') export class PlayerCtl extends Component { @property(Camera) private camera: Camera | null = null; @property(Node) private Container: 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 totalDestroy: number = 0; private startTouchPos: Vec2 = null; private moveDistance: number = 0; private swipeThreshold: number = 10; // 滑动阈值 start() { // 获取场景中的摄像头 const mainCameraNode = find('Main Camera'); if (mainCameraNode) { this.camera = mainCameraNode.getComponent(Camera); } this.Container = find("Container"); // 监听触摸开始事件 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) { // 确保获取的是第一个触摸点 this.startTouchPos = event.getLocation(); } //滑动屏幕让当前层类似于2048游戏中的上下左右移动,并不合并/消除 onTouchMove(event: EventTouch) { const currentTouchPos = event.getLocation(); if (this.startTouchPos) { 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) 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; // 向左 } 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) { let map = this.Container.getComponent(CreateMap).GetMap(); let maxKIJ = this.Container.getComponent(CreateMap).GetMaxKIJ(); for (let k = 0; 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); } } } } } // 更新地图数据 this.Container.getComponent(CreateMap).setMap(tempMap, k); //延时更新颜色 setTimeout(() => { this.Container.getComponent(CreateMap).changeColor(this.layerIndex); }, 250); } } //发射射线检测判断物体是否可消除 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(); } console.log('发射了射线'); } //多层堆叠的map,但是要从2d视角检测当前方块四方向是否有连续同色,采用BFS checkNearCube(Pos: Vec3) { console.log(Pos); let map = this.Container.getComponent(CreateMap).GetMap(); let maxKIJ = this.Container.getComponent(CreateMap).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 < this.layerIndex; 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 < this.layerIndex; 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() { if (this.waitDestroy.length >= 3) { let map = this.Container.getComponent(CreateMap).GetMap(); this.waitDestroy.forEach(cube => { if (cube) { map[cube.x][cube.y][cube.z].destroy(); map[cube.x][cube.y][cube.z] = null;//销毁的方块所在位置置空 if (cube.x + 1 === this.layerIndex) { this.totalDestroy++; console.log('当前层销毁了' + this.totalDestroy + '个'); } // this.score += 10; // 假设每销毁一个块加10分 } }); this.calculateScore(this.waitDestroy.length); } this.waitDestroy = []; // 清空等待销毁的块列表 if (this.totalDestroy / (15 * 7) > 0.8)//消除表层80%,解锁下层 { let maxKIJ = this.Container.getComponent(CreateMap).GetMaxKIJ(); if (this.layerIndex < maxKIJ.x) { this.layerIndex++; UpdateLayer.instance.Update_Layer(this.layerIndex); this.totalDestroy = 0; } } //延时更新颜色 setTimeout(() => { this.Container.getComponent(CreateMap).changeColor(this.layerIndex); }, 250); } //加分 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); } }