| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- 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);
- }
- }
|