PlayerCtl.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. import { _decorator, Component, Node, PhysicsSystem, Camera, EventTouch, find, geometry, Layers, Vec3, Vec2 } from 'cc';
  2. import { CreateMap } from './CreateMap';
  3. import { CubeInfo } from './CubeInfo';
  4. import { UpdateLayer } from './UpdateLayer';
  5. import { UpdateScore } from './UpdateScore';
  6. import { ShowTip } from './ShowTip';
  7. const { ccclass, property } = _decorator;
  8. @ccclass('PlayerCtl')
  9. export class PlayerCtl extends Component {
  10. @property(Camera)
  11. private camera: Camera | null = null;
  12. @property(Node)
  13. private Container: Node = null;
  14. private dir: number[][] = [[0, 0, 1], [0, 1, 0], [0, 0, -1], [0, -1, 0]];
  15. private waitDestroy: Vec3[] = [];//等待销毁的所有节点
  16. public layerIndex: number = 1;
  17. private totalDestroy: number = 0;
  18. private startTouchPos: Vec2 = null;
  19. private moveDistance: number = 0;
  20. private swipeThreshold: number = 10; // 滑动阈值
  21. start() {
  22. // 获取场景中的摄像头
  23. const mainCameraNode = find('Main Camera');
  24. if (mainCameraNode) {
  25. this.camera = mainCameraNode.getComponent(Camera);
  26. }
  27. this.Container = find("Container");
  28. // 监听触摸开始事件
  29. this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
  30. this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
  31. this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
  32. }
  33. onTouchStart(event: EventTouch) {
  34. // 确保获取的是第一个触摸点
  35. this.startTouchPos = event.getLocation();
  36. }
  37. //滑动屏幕让当前层类似于2048游戏中的上下左右移动,并不合并/消除
  38. onTouchMove(event: EventTouch) {
  39. const currentTouchPos = event.getLocation();
  40. if (this.startTouchPos) {
  41. const moveVector = new Vec2(currentTouchPos.x - this.startTouchPos.x, currentTouchPos.y - this.startTouchPos.y);
  42. this.moveDistance = moveVector.length(); // 更新滑动距离
  43. console.log("触摸屏幕");
  44. }
  45. }
  46. onTouchEnd(event: EventTouch) {
  47. if (!this.startTouchPos) return;
  48. const currentTouchPos = event.getLocation();
  49. const moveVector = new Vec2(currentTouchPos.x - this.startTouchPos.x, currentTouchPos.y - this.startTouchPos.y);
  50. if (this.moveDistance > this.swipeThreshold) {
  51. const direction = moveVector.normalize(); // 返回方向向量
  52. this.handleSwipe(direction); // 处理滑动
  53. }
  54. else {
  55. this.shootRay(event);
  56. }
  57. this.startTouchPos = null; // 重置触摸位置
  58. this.moveDistance = 0; // 重置滑动距离
  59. }
  60. handleSwipe(direction: Vec2) {
  61. // 确定滑动方向对应的索引
  62. let directionIndex = -1;
  63. const horizontalThreshold = 0.7;
  64. const verticalThreshold = 0.7;
  65. if (Math.abs(direction.x) > horizontalThreshold && Math.abs(direction.y) < verticalThreshold) {
  66. // 主要是水平方向移动
  67. if (direction.x < 0) directionIndex = 3; // 向右
  68. else if (direction.x > 0) directionIndex = 1; // 向左
  69. } else if (Math.abs(direction.y) > verticalThreshold && Math.abs(direction.x) < horizontalThreshold) {
  70. // 主要是垂直方向移动
  71. if (direction.y < 0) directionIndex = 2; // 向下
  72. else if (direction.y > 0) directionIndex = 0; // 向上
  73. }
  74. if (directionIndex !== -1) {
  75. this.moveLayer(directionIndex);
  76. }
  77. }
  78. //已解锁的层都需要移动
  79. moveLayer(directionIndex) {
  80. let map = this.Container.getComponent(CreateMap).GetMap();
  81. let maxKIJ = this.Container.getComponent(CreateMap).GetMaxKIJ();
  82. for (let k = 0; k < this.layerIndex; k++) {
  83. // 创建一个临时数组来存储移动后的方块状态
  84. let tempMap = new Array(maxKIJ.y).fill(null).map(() => new Array(maxKIJ.z).fill(null));
  85. // 左右移动
  86. if (directionIndex === 3 || directionIndex === 1) {
  87. for (let i = 0; i < maxKIJ.y; i++) {
  88. let newRow = [];
  89. for (let j = 0; j < maxKIJ.z; j++) {
  90. let cube = map[k][i][j];
  91. if (cube) {
  92. newRow.push({ cube });
  93. }
  94. }
  95. // 向左移动
  96. if (directionIndex === 3) {
  97. for (let j = 0; j < maxKIJ.z; j++) {
  98. let item = newRow.shift(); // 取出最左边的方块
  99. if (item) {
  100. tempMap[i][j] = item.cube;
  101. item.cube.getComponent(CubeInfo).setPos(k, i, j);
  102. }
  103. }
  104. }
  105. // 向右移动
  106. else {
  107. for (let j = maxKIJ.z - 1; j >= 0; j--) {
  108. let item = newRow.pop(); // 取出最右边的方块
  109. if (item) {
  110. tempMap[i][j] = item.cube;
  111. item.cube.getComponent(CubeInfo).setPos(k, i, j);
  112. }
  113. }
  114. }
  115. }
  116. }
  117. // 上下移动
  118. else if (directionIndex === 0 || directionIndex === 2) {
  119. for (let j = 0; j < maxKIJ.z; j++) {
  120. let newCol = [];
  121. for (let i = 0; i < maxKIJ.y; i++) {
  122. let cube = map[k][i][j];
  123. if (cube) {
  124. newCol.push({ cube });
  125. }
  126. }
  127. // 向上移动
  128. if (directionIndex === 0) {
  129. for (let i = 0; i < maxKIJ.y; i++) {
  130. let item = newCol.shift(); // 取出最下面的方块
  131. if (item) {
  132. tempMap[i][j] = item.cube;
  133. item.cube.getComponent(CubeInfo).setPos(k, i, j);
  134. }
  135. }
  136. }
  137. // 向下移动
  138. else {
  139. for (let i = maxKIJ.y - 1; i >= 0; i--) {
  140. let item = newCol.pop(); // 取出最上面的方块
  141. if (item) {
  142. tempMap[i][j] = item.cube;
  143. item.cube.getComponent(CubeInfo).setPos(k, i, j);
  144. }
  145. }
  146. }
  147. }
  148. }
  149. // 更新地图数据
  150. this.Container.getComponent(CreateMap).setMap(tempMap, k);
  151. //延时更新颜色
  152. setTimeout(() => {
  153. this.Container.getComponent(CreateMap).changeColor(this.layerIndex);
  154. }, 250);
  155. }
  156. }
  157. //发射射线检测判断物体是否可消除
  158. shootRay(event: EventTouch) {
  159. if (!this.camera) return;
  160. let ray = new geometry.Ray();
  161. this.camera.screenPointToRay(event.getLocationX(), event.getLocationY(), ray);
  162. const index = Layers.nameToLayer('Cube');
  163. const mask = 1 << index;
  164. const maxDistance = 10000000;
  165. const queryTrigger = true;
  166. if (PhysicsSystem.instance.raycastClosest(ray, mask, maxDistance, queryTrigger)) {
  167. const raycastClosestResult = PhysicsSystem.instance.raycastClosestResult;
  168. const hitPoint = raycastClosestResult.hitPoint;
  169. const hitNormal = raycastClosestResult.hitNormal;
  170. const collider = raycastClosestResult.collider;
  171. const distance = raycastClosestResult.distance;
  172. console.log(collider.node.name);
  173. //检测周边四个方向相同颜色的物体
  174. this.checkNearCube(collider.node.getComponent(CubeInfo).getPos());
  175. //拿取到所有连续颜色相同的物体,进行销毁
  176. this.destroyCollectedCubes();
  177. }
  178. console.log('发射了射线');
  179. }
  180. //多层堆叠的map,但是要从2d视角检测当前方块四方向是否有连续同色,采用BFS
  181. checkNearCube(Pos: Vec3) {
  182. console.log(Pos);
  183. let map = this.Container.getComponent(CreateMap).GetMap();
  184. let maxKIJ = this.Container.getComponent(CreateMap).GetMaxKIJ();
  185. let currentCubeInfo = map[Pos.x][Pos.y][Pos.z]?.getComponent(CubeInfo);
  186. if (!currentCubeInfo || Pos.x >= this.layerIndex) return;
  187. let cubeId = currentCubeInfo.getId();
  188. let count = 0;
  189. let toMarkAsNull: Vec3[] = [];
  190. let queue: Vec3[] = [];
  191. queue.push(Pos);
  192. let visited: boolean[][][] = new Array(maxKIJ.x).fill(false).map(() => new Array(maxKIJ.y).fill(false).map(() => new Array(maxKIJ.z).fill(false)));
  193. while (queue.length > 0) {
  194. let currentPos = queue.shift();
  195. if (!currentPos) continue;
  196. let x = currentPos.x;
  197. let y = currentPos.y;
  198. let z = currentPos.z;
  199. // 检查边界条件和是否已经访问过
  200. if (x < 0 || x >= maxKIJ.x || y < 0 || y >= maxKIJ.y || z < 0 || z >= maxKIJ.z || visited[x][y][z]) continue;
  201. let cubeInfo = map[x][y][z]?.getComponent(CubeInfo);
  202. if (cubeInfo && cubeInfo.getId() === cubeId) {
  203. count++;
  204. toMarkAsNull.push(new Vec3(x, y, z));
  205. this.dir.forEach(d => {
  206. let newX = x + d[0];
  207. let newY = y + d[1];
  208. let newZ = z + d[2];
  209. // 确保新的坐标在边界内,并且目标块不为空,并且是已解锁
  210. 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()) {
  211. queue.push(new Vec3(newX, newY, newZ));
  212. }
  213. //旁边无方块
  214. else {
  215. //判断更深层次
  216. for (let i = 1; i < this.layerIndex; i++) {
  217. 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()) {
  218. queue.push(new Vec3(newX + i, newY, newZ));
  219. }
  220. }
  221. //判断更浅层次
  222. for (let i = 1; i < this.layerIndex; i++) {
  223. 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()) {
  224. queue.push(new Vec3(newX - i, newY, newZ));
  225. }
  226. }
  227. }
  228. });
  229. visited[x][y][z] = true;
  230. }
  231. }
  232. //连续颜色相同方块大于等于三个时,将每个方块放入待销毁数组
  233. if (count >= 3) {
  234. toMarkAsNull.forEach(pos => {
  235. this.waitDestroy.push(new Vec3(pos.x, pos.y, pos.z));
  236. });
  237. }
  238. // else {
  239. // // 如果数量小于 3,确保不进行错误操作
  240. // toMarkAsNull.forEach(pos => {
  241. // // 检查 map 中对应位置是否为 null,如果为 null 则不进行任何操作
  242. // if (map[pos.x] && map[pos.x][pos.y] && map[pos.x][pos.y][pos.z]) {
  243. // if (!this.waitDestroy.some(item => item === map[pos.x][pos.y][pos.z])) {
  244. // // 保持方块状态不变
  245. // }
  246. // }
  247. // });
  248. // }
  249. }
  250. //销毁方块
  251. destroyCollectedCubes() {
  252. if (this.waitDestroy.length >= 3) {
  253. let map = this.Container.getComponent(CreateMap).GetMap();
  254. this.waitDestroy.forEach(cube => {
  255. if (cube) {
  256. map[cube.x][cube.y][cube.z].destroy();
  257. map[cube.x][cube.y][cube.z] = null;//销毁的方块所在位置置空
  258. if (cube.x + 1 === this.layerIndex) {
  259. this.totalDestroy++;
  260. console.log('当前层销毁了' + this.totalDestroy + '个');
  261. }
  262. // this.score += 10; // 假设每销毁一个块加10分
  263. }
  264. });
  265. this.calculateScore(this.waitDestroy.length);
  266. }
  267. this.waitDestroy = []; // 清空等待销毁的块列表
  268. if (this.totalDestroy / (15 * 7) > 0.8)//消除表层80%,解锁下层
  269. {
  270. let maxKIJ = this.Container.getComponent(CreateMap).GetMaxKIJ();
  271. if (this.layerIndex < maxKIJ.x) {
  272. this.layerIndex++;
  273. UpdateLayer.instance.Update_Layer(this.layerIndex);
  274. this.totalDestroy = 0;
  275. }
  276. }
  277. //延时更新颜色
  278. setTimeout(() => {
  279. this.Container.getComponent(CreateMap).changeColor(this.layerIndex);
  280. }, 250);
  281. }
  282. //加分
  283. calculateScore(length: number) {
  284. let score = 0;
  285. //销毁后进行加分,3-5个为基础分每个方块5分,6-8个每个方块多算10分,9-15个每个方块多算20分,16个以上每个方块多算50分
  286. if (length >= 3 && length <= 5) {
  287. ShowTip.instance.Show_Tip('Good');
  288. score = length * 5;
  289. }
  290. else if (length >= 6 && length <= 8) {
  291. ShowTip.instance.Show_Tip('Great');
  292. score = length * 15;
  293. }
  294. else if (length >= 9 && length <= 15) {
  295. ShowTip.instance.Show_Tip('Unbeliveable');
  296. score = length * 25;
  297. } else if (length >= 16) {
  298. ShowTip.instance.Show_Tip('excellent');
  299. score = length * 55;
  300. }
  301. UpdateScore.instance.Update_Score(score);
  302. }
  303. }