PlayerCtl.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. import { _decorator, Component, Node, PhysicsSystem, Camera, EventTouch, find, geometry, Layers, Vec3, Vec2, quat, DirectionalLight, Quat, AudioSource, AudioClip } 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. import { EasyColorStrategy, HardColorStrategy, NormalColorStrategy, StrategyManager } from './StrategyManager';
  8. import { GameState, PlayState, StateManager } from './StateManager';
  9. import { UIManager } from '../UIFrameWork/UIManager';
  10. import { LoadRes } from '../Config/LoadRes';
  11. import ch_audio from '../../ch/audio/audio';
  12. const { ccclass, property } = _decorator;
  13. @ccclass('PlayerCtl')
  14. export class PlayerCtl extends Component {
  15. public static instance: PlayerCtl = null;
  16. private cameraNode: Node = null;
  17. @property(Camera)
  18. private camera: Camera | null = null;
  19. private light: Node = null;
  20. private dir: number[][] = [[0, 0, 1], [0, 1, 0], [0, 0, -1], [0, -1, 0]];
  21. private waitDestroy: Vec3[] = [];//等待销毁的所有节点
  22. public layerIndex: number = 1;//已开启层数
  23. private surfaceLayer: number = 1;//表层
  24. private needMoveLayer: number = 0;//
  25. private totalDestroy: number = 0;
  26. private startTouchPos: Vec2 = null;
  27. private moveDistance: number = 0;
  28. private swipeThreshold: number = 50; // 滑动阈值
  29. public touchLock: boolean = true;//触摸锁定状态
  30. onLoad() {
  31. PlayerCtl.instance = this;
  32. // 获取场景中的主光源
  33. this.light = find('Main Light');
  34. // 获取场景中的主摄像头
  35. this.cameraNode = find('Main Camera');
  36. if (this.cameraNode) {
  37. this.camera = this.cameraNode.getComponent(Camera);
  38. }
  39. // 监听触摸开始事件
  40. this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
  41. this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
  42. this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
  43. }
  44. onTouchStart(event: EventTouch) {
  45. // 确保获取的是第一个触摸点
  46. if (!this.touchLock&&StateManager.getInstance().getState() instanceof PlayState) {
  47. this.startTouchPos = event.getLocation();
  48. }
  49. }
  50. //滑动屏幕让当前层类似于2048游戏中的上下左右移动,并不合并/消除
  51. onTouchMove(event: EventTouch) {
  52. const currentTouchPos = event.getLocation();
  53. if (this.startTouchPos&&StateManager.getInstance().getState() instanceof PlayState) {
  54. const moveVector = new Vec2(currentTouchPos.x - this.startTouchPos.x, currentTouchPos.y - this.startTouchPos.y);
  55. this.moveDistance = moveVector.length(); // 更新滑动距离
  56. console.log("触摸屏幕");
  57. }
  58. }
  59. onTouchEnd(event: EventTouch) {
  60. if (!this.startTouchPos || this.touchLock || !(StateManager.getInstance().getState() instanceof PlayState)) return;
  61. //移动动画在执行时应关闭触摸判断
  62. const currentTouchPos = event.getLocation();
  63. const moveVector = new Vec2(currentTouchPos.x - this.startTouchPos.x, currentTouchPos.y - this.startTouchPos.y);
  64. if (this.moveDistance > this.swipeThreshold) {
  65. const direction = moveVector.normalize(); // 返回方向向量
  66. this.handleSwipe(direction); // 处理滑动
  67. }
  68. else {
  69. this.shootRay(event);
  70. }
  71. this.startTouchPos = null; // 重置触摸位置
  72. this.moveDistance = 0; // 重置滑动距离
  73. }
  74. handleSwipe(direction: Vec2) {
  75. // 确定滑动方向对应的索引
  76. let directionIndex = -1;
  77. const horizontalThreshold = 0.7;
  78. const verticalThreshold = 0.7;
  79. if (Math.abs(direction.x) > horizontalThreshold && Math.abs(direction.y) < verticalThreshold) {
  80. // 主要是水平方向移动
  81. if (direction.x < 0) {
  82. directionIndex = 3; // 向左
  83. }
  84. else if (direction.x > 0) {
  85. directionIndex = 1; // 向右
  86. // this.light.setRotationFromEuler(new Vec3(10, 0, 0));
  87. }
  88. } else if (Math.abs(direction.y) > verticalThreshold && Math.abs(direction.x) < horizontalThreshold) {
  89. // 主要是垂直方向移动
  90. if (direction.y < 0) directionIndex = 2; // 向下
  91. else if (direction.y > 0) directionIndex = 0; // 向上
  92. }
  93. if (directionIndex !== -1) {
  94. this.moveLayer(directionIndex);
  95. }
  96. }
  97. //已解锁的层都需要移动
  98. // moveLayer(directionIndex) {
  99. // this.touchLock = true;
  100. // let map = CreateMap.getInstance().GetMap();
  101. // let maxKIJ = CreateMap.getInstance().GetMaxKIJ();
  102. // for (let k = this.surfaceLayer - 1; k < this.layerIndex; k++) {
  103. // // 创建一个临时数组来存储移动后的方块状态
  104. // let tempMap = new Array(maxKIJ.y).fill(null).map(() => new Array(maxKIJ.z).fill(null));
  105. // // 左右移动
  106. // if (directionIndex === 3 || directionIndex === 1) {
  107. // for (let i = 0; i < maxKIJ.y; i++) {
  108. // let newRow = [];
  109. // for (let j = 0; j < maxKIJ.z; j++) {
  110. // let cube = map[k][i][j];
  111. // if (cube) {
  112. // newRow.push({ cube });
  113. // }
  114. // }
  115. // // 向左移动
  116. // if (directionIndex === 3) {
  117. // for (let j = 0; j < maxKIJ.z; j++) {
  118. // let item = newRow.shift(); // 取出最左边的方块
  119. // if (item) {
  120. // tempMap[i][j] = item.cube;
  121. // item.cube.getComponent(CubeInfo).setPos(k, i, j);
  122. // }
  123. // }
  124. // }
  125. // // 向右移动
  126. // else {
  127. // for (let j = maxKIJ.z - 1; j >= 0; j--) {
  128. // let item = newRow.pop(); // 取出最右边的方块
  129. // if (item) {
  130. // tempMap[i][j] = item.cube;
  131. // item.cube.getComponent(CubeInfo).setPos(k, i, j);
  132. // }
  133. // }
  134. // }
  135. // }
  136. // }
  137. // // 上下移动
  138. // else if (directionIndex === 0 || directionIndex === 2) {
  139. // for (let j = 0; j < maxKIJ.z; j++) {
  140. // let newCol = [];
  141. // for (let i = 0; i < maxKIJ.y; i++) {
  142. // let cube = map[k][i][j];
  143. // if (cube) {
  144. // newCol.push({ cube });
  145. // }
  146. // }
  147. // // 向上移动
  148. // if (directionIndex === 0) {
  149. // for (let i = 0; i < maxKIJ.y; i++) {
  150. // let item = newCol.shift(); // 取出最下面的方块
  151. // if (item) {
  152. // tempMap[i][j] = item.cube;
  153. // item.cube.getComponent(CubeInfo).setPos(k, i, j);
  154. // }
  155. // }
  156. // }
  157. // // 向下移动
  158. // else {
  159. // for (let i = maxKIJ.y - 1; i >= 0; i--) {
  160. // let item = newCol.pop(); // 取出最上面的方块
  161. // if (item) {
  162. // tempMap[i][j] = item.cube;
  163. // item.cube.getComponent(CubeInfo).setPos(k, i, j);
  164. // }
  165. // }
  166. // }
  167. // }
  168. // }
  169. // // // 更新地图数据
  170. // CreateMap.getInstance().setMap(tempMap, k, this.needMoveLayer);
  171. // }
  172. // //更新颜色
  173. // CreateMap.getInstance().changeColor(this.surfaceLayer-1,this.layerIndex);
  174. // }
  175. moveLayer(directionIndex) {
  176. this.touchLock = true;
  177. let map = CreateMap.getInstance().GetMap();
  178. let maxKIJ = CreateMap.getInstance().GetMaxKIJ();
  179. for (let k = this.surfaceLayer - 1; k < this.layerIndex; k++) {
  180. let tempMap = new Array(maxKIJ.y).fill(null).map(() => new Array(maxKIJ.z).fill(null));
  181. // 左右移动
  182. if (directionIndex === 3 || directionIndex === 1) {
  183. for (let i = 0; i < maxKIJ.y; i++) {
  184. let newRow = [];
  185. for (let j = 0; j < maxKIJ.z; j++) {
  186. let cube = map[k][i][j];
  187. if (cube) {
  188. newRow.push({ cube });
  189. }
  190. }
  191. // 向左移动
  192. if (directionIndex === 3) {
  193. for (let j = 0; j < maxKIJ.z; j++) {
  194. let item = newRow.shift(); // 取出最左边的方块
  195. if (item) {
  196. tempMap[i][j] = item.cube;
  197. item.cube.getComponent(CubeInfo).setPos(k, i, j);
  198. }
  199. }
  200. }
  201. // 向右移动
  202. else {
  203. for (let j = maxKIJ.z - 1; j >= 0; j--) {
  204. let item = newRow.pop(); // 取出最右边的方块
  205. if (item) {
  206. tempMap[i][j] = item.cube;
  207. item.cube.getComponent(CubeInfo).setPos(k, i, j);
  208. }
  209. }
  210. }
  211. }
  212. }
  213. // 上下移动
  214. else if (directionIndex === 0 || directionIndex === 2) {
  215. for (let j = 0; j < maxKIJ.z; j++) {
  216. let newCol = [];
  217. for (let i = 0; i < maxKIJ.y; i++) {
  218. let cube = map[k][i][j];
  219. if (cube) {
  220. newCol.push({ cube });
  221. }
  222. }
  223. // 向上移动
  224. if (directionIndex === 0) {
  225. for (let i = 0; i < maxKIJ.y; i++) {
  226. let item = newCol.shift(); // 取出最下面的方块
  227. if (item) {
  228. tempMap[i][j] = item.cube;
  229. item.cube.getComponent(CubeInfo).setPos(k, i, j);
  230. }
  231. }
  232. }
  233. // 向下移动
  234. else {
  235. for (let i = maxKIJ.y - 1; i >= 0; i--) {
  236. let item = newCol.pop(); // 取出最上面的方块
  237. if (item) {
  238. tempMap[i][j] = item.cube;
  239. item.cube.getComponent(CubeInfo).setPos(k, i, j);
  240. }
  241. }
  242. }
  243. }
  244. }
  245. CreateMap.getInstance().setMap(tempMap, k, this.needMoveLayer);
  246. }
  247. CreateMap.getInstance().changeColor(this.surfaceLayer - 1, this.layerIndex);
  248. }
  249. //发射射线检测判断物体是否可消除
  250. shootRay(event: EventTouch) {
  251. if (!this.camera) return;
  252. let ray = new geometry.Ray();
  253. this.camera.screenPointToRay(event.getLocationX(), event.getLocationY(), ray);
  254. const index = Layers.nameToLayer('Cube');
  255. const mask = 1 << index;
  256. const maxDistance = 10000000;
  257. const queryTrigger = true;
  258. if (PhysicsSystem.instance.raycastClosest(ray, mask, maxDistance, queryTrigger)) {
  259. const raycastClosestResult = PhysicsSystem.instance.raycastClosestResult;
  260. const hitPoint = raycastClosestResult.hitPoint;
  261. const hitNormal = raycastClosestResult.hitNormal;
  262. const collider = raycastClosestResult.collider;
  263. const distance = raycastClosestResult.distance;
  264. console.log(collider.node.name);
  265. //检测周边四个方向相同颜色的物体
  266. this.checkNearCube(collider.node.getComponent(CubeInfo).getPos());
  267. //拿取到所有连续颜色相同的物体,进行销毁
  268. this.destroyCollectedCubes();
  269. //最多允许同时存在3层,如果当前有三层未销毁完,但已开启第四层,消除最上层所有元素且不计分
  270. this.judgeSurface();//得出表层
  271. if (this.calcDifference())//超出三层
  272. {
  273. console.log("相差层数大于3层");
  274. //弹出广告界面,不看广告游戏结束
  275. UIManager.Instance.ShowUI("ad", LoadRes.getInstance().adPanel);
  276. }
  277. }
  278. console.log('发射了射线');
  279. }
  280. //多层堆叠的map,但是要从2d视角检测当前方块四方向是否有连续同色,采用BFS
  281. checkNearCube(Pos: Vec3) {
  282. console.log(Pos);
  283. let map = CreateMap.getInstance().GetMap();
  284. let maxKIJ = CreateMap.getInstance().GetMaxKIJ();
  285. let currentCubeInfo = map[Pos.x][Pos.y][Pos.z]?.getComponent(CubeInfo);
  286. if (!currentCubeInfo || Pos.x >= this.layerIndex) return;
  287. let cubeId = currentCubeInfo.getId();
  288. let count = 0;
  289. let toMarkAsNull: Vec3[] = [];
  290. let queue: Vec3[] = [];
  291. queue.push(Pos);
  292. let visited: boolean[][][] = new Array(maxKIJ.x).fill(false).map(() => new Array(maxKIJ.y).fill(false).map(() => new Array(maxKIJ.z).fill(false)));
  293. while (queue.length > 0) {
  294. let currentPos = queue.shift();
  295. if (!currentPos) continue;
  296. let x = currentPos.x;
  297. let y = currentPos.y;
  298. let z = currentPos.z;
  299. // 检查边界条件和是否已经访问过
  300. if (x < 0 || x >= maxKIJ.x || y < 0 || y >= maxKIJ.y || z < 0 || z >= maxKIJ.z || visited[x][y][z]) continue;
  301. let cubeInfo = map[x][y][z]?.getComponent(CubeInfo);
  302. if (cubeInfo && cubeInfo.getId() === cubeId) {
  303. count++;
  304. toMarkAsNull.push(new Vec3(x, y, z));
  305. this.dir.forEach(d => {
  306. let newX = x + d[0];
  307. let newY = y + d[1];
  308. let newZ = z + d[2];
  309. // 确保新的坐标在边界内,并且目标块不为空,并且是已解锁
  310. 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()) {
  311. queue.push(new Vec3(newX, newY, newZ));
  312. }
  313. //旁边无方块
  314. else {
  315. //判断更深层次
  316. for (let i = 1; i < 4; i++) {
  317. 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()) {
  318. queue.push(new Vec3(newX + i, newY, newZ));
  319. }
  320. }
  321. //判断更浅层次
  322. for (let i = 1; i < 4; i++) {
  323. 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()) {
  324. queue.push(new Vec3(newX - i, newY, newZ));
  325. }
  326. }
  327. }
  328. });
  329. visited[x][y][z] = true;
  330. }
  331. }
  332. //连续颜色相同方块大于等于三个时,将每个方块放入待销毁数组
  333. if (count >= 3) {
  334. toMarkAsNull.forEach(pos => {
  335. this.waitDestroy.push(new Vec3(pos.x, pos.y, pos.z));
  336. });
  337. }
  338. // else {
  339. // // 如果数量小于 3,确保不进行错误操作
  340. // toMarkAsNull.forEach(pos => {
  341. // // 检查 map 中对应位置是否为 null,如果为 null 则不进行任何操作
  342. // if (map[pos.x] && map[pos.x][pos.y] && map[pos.x][pos.y][pos.z]) {
  343. // if (!this.waitDestroy.some(item => item === map[pos.x][pos.y][pos.z])) {
  344. // // 保持方块状态不变
  345. // }
  346. // }
  347. // });
  348. // }
  349. }
  350. //销毁方块
  351. destroyCollectedCubes() {
  352. let map = CreateMap.getInstance().GetMap();
  353. if (this.waitDestroy.length >= 3) {
  354. if(ch_audio.getInstance().volumeEffect)
  355. {
  356. ch_audio.getInstance().playOneShot('Break');
  357. }
  358. this.waitDestroy.forEach(cube => {
  359. if (cube) {
  360. //调用爆炸特效
  361. // map[cube.x][cube.y][cube.z].getComponent(CubeInfo).triggerDissolve();
  362. CreateMap.getInstance().destroyNode(cube);
  363. if (cube.x + 1 === this.layerIndex) {
  364. this.totalDestroy++;
  365. console.log('当前层销毁了' + this.totalDestroy + '个');
  366. }
  367. // this.score += 10; // 假设每销毁一个块加10分
  368. }
  369. });
  370. this.calculateScore(this.waitDestroy.length);
  371. }
  372. this.waitDestroy = []; // 清空等待销毁的块列表
  373. let maxKIJ = CreateMap.getInstance().GetMaxKIJ();
  374. if (this.totalDestroy / (maxKIJ.y * maxKIJ.z) > 0.8)//消除表层80%,解锁下层
  375. {
  376. this.layerIndex++;
  377. UpdateLayer.instance.Update_Layer(this.layerIndex);
  378. this.totalDestroy = 0;
  379. console.log("调用新增实例层");
  380. }
  381. //如果表层被玩家自己消除完了,下面所有层都需要上移
  382. if (this.CalcSurface()) {
  383. CreateMap.getInstance().initNewLayer(maxKIJ.x, this.needMoveLayer);
  384. this.needMoveLayer++;//需移动的层数+1
  385. let maxK = CreateMap.getInstance().GetMaxKIJ().x;
  386. for (let k = this.surfaceLayer - 1; k < maxK; k++) {
  387. CreateMap.getInstance().setMap(map[k], k, this.needMoveLayer);
  388. }
  389. }
  390. //更新颜色
  391. CreateMap.getInstance().changeColor(this.surfaceLayer - 1, this.layerIndex);
  392. }
  393. //加分
  394. calculateScore(length: number) {
  395. let score = 0;
  396. //销毁后进行加分,3-5个为基础分每个方块5分,6-8个每个方块多算10分,9-15个每个方块多算20分,16个以上每个方块多算50分
  397. if (length >= 3 && length <= 5) {
  398. ShowTip.instance.Show_Tip('Good');
  399. score = length * 5;
  400. }
  401. else if (length >= 6 && length <= 8) {
  402. ShowTip.instance.Show_Tip('Great');
  403. score = length * 15;
  404. }
  405. else if (length >= 9 && length <= 15) {
  406. ShowTip.instance.Show_Tip('Unbeliveable');
  407. score = length * 25;
  408. } else if (length >= 16) {
  409. ShowTip.instance.Show_Tip('excellent');
  410. score = length * 55;
  411. }
  412. UpdateScore.instance.Update_Score(score);
  413. }
  414. //判断哪一层是表层
  415. judgeSurface() {
  416. let maxKIJ = CreateMap.getInstance().GetMaxKIJ();
  417. let map = CreateMap.getInstance().GetMap();
  418. for (let k = 0; k < this.layerIndex; k++) {
  419. for (let i = 0; i < maxKIJ.y; i++) {
  420. for (let j = 0; j < maxKIJ.z; j++) {
  421. if (map[k][i][j] !== null) {
  422. this.surfaceLayer = k + 1;//更新表层
  423. console.log("表层是" + this.surfaceLayer);
  424. return;
  425. }
  426. }
  427. }
  428. }
  429. }
  430. CalcSurface(): boolean {
  431. let maxKIJ = CreateMap.getInstance().GetMaxKIJ();
  432. let map = CreateMap.getInstance().GetMap();
  433. for (let i = 0; i < maxKIJ.y; i++) {
  434. for (let j = 0; j < maxKIJ.z; j++) {
  435. if (map[this.surfaceLayer - 1][i][j] !== null) {
  436. //表层没被消除完
  437. return false;
  438. }
  439. }
  440. }
  441. CreateMap.getInstance().setMap(map[this.surfaceLayer - 1], this.surfaceLayer - 1, this.needMoveLayer);
  442. this.surfaceLayer++;//更新表层
  443. return true;
  444. }
  445. //计算深度差
  446. calcDifference(): boolean {
  447. return (this.layerIndex - (this.surfaceLayer - 1)) > 1 ? true : false;
  448. }
  449. //弹出广告界面,销毁表层方块
  450. destroySurfaceCube(index: number) {
  451. let maxKIJ = CreateMap.getInstance().GetMaxKIJ();
  452. let map = CreateMap.getInstance().GetMap();
  453. for (let i = 0; i < maxKIJ.y; i++) {
  454. for (let j = 0; j < maxKIJ.z; j++) {
  455. if (map[index][i][j] !== null) {
  456. console.log("应该销毁第" + index + "层");
  457. //调用爆炸特效
  458. CreateMap.getInstance().destroyNode(new Vec3(index, i, j));
  459. }
  460. }
  461. }
  462. this.surfaceLayer++;//更新表层
  463. CreateMap.getInstance().initNewLayer(maxKIJ.x, this.needMoveLayer);
  464. this.needMoveLayer++;
  465. }
  466. //看了广告要执行的内容
  467. public onAdFinish() {
  468. //销毁表层
  469. this.destroySurfaceCube(this.surfaceLayer - 1);
  470. //下层所有层向上移动一层
  471. let maxKIJ = CreateMap.getInstance().GetMaxKIJ();
  472. let map = CreateMap.getInstance().GetMap();
  473. for (let k = this.surfaceLayer - 1; k < maxKIJ.x; k++) {
  474. CreateMap.getInstance().setMap(map[k], k, this.needMoveLayer);
  475. }
  476. }
  477. }