GameCtl.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. import { _decorator, BoxCollider, Camera, Component, director, EventTouch, find, Game, geometry, Layers, Node, PhysicsSystem, Quat, RigidBody, Size, tween, UITransform, v3, Vec3 } from 'cc';
  2. import { gui } from '../../core/ui/ui';
  3. import { UI_Idioms } from '../ui/UI_Idioms/UI_Idioms';
  4. import { UI_Main } from '../ui/UI_Main/UI_Main';
  5. import { Container_Manager } from './Container_Manager';
  6. import { Cube_Infor, Cube_State } from './Cube_Infor';
  7. import { Hall } from '../hall/Hall';
  8. const { ccclass, property } = _decorator;
  9. @ccclass('GameCtl')
  10. export class GameCtl extends Component {
  11. static instance: GameCtl = null;
  12. @property(Camera)
  13. camera: Camera = null;
  14. @property([Node])
  15. Ani: Node[] = [];
  16. canTouch: boolean = true;
  17. Container: Container_Manager;
  18. onLoad() {
  19. GameCtl.instance = this;
  20. console.log(find('Ani'));
  21. console.log('Camera value in onLoad:', this.camera);
  22. this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
  23. this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
  24. this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
  25. this.Container = find('Container').getComponent(Container_Manager);
  26. }
  27. update(deltaTime: number) {
  28. }
  29. onTouchStart(event: EventTouch) {
  30. }
  31. onTouchMove(event: EventTouch) {
  32. }
  33. onTouchEnd(event: EventTouch) {
  34. if (this.canTouch) {
  35. this.shootRay(event);
  36. }
  37. }
  38. //发射射线检测判断物体是否可消除
  39. shootRay(event: EventTouch) {
  40. if (!this.camera) return;
  41. let ray = new geometry.Ray();
  42. this.camera.screenPointToRay(event.getLocationX(), event.getLocationY(), ray);
  43. const index = Layers.nameToLayer('Cube');
  44. const cubeMask = 2 << index;
  45. const maxDistance = 100000;
  46. const queryTrigger = false;
  47. if (PhysicsSystem.instance.raycastClosest(ray, cubeMask, maxDistance, queryTrigger)) {
  48. const raycastClosestResult = PhysicsSystem.instance.raycastClosestResult;
  49. const hitPoint = raycastClosestResult.hitPoint;
  50. const hitNormal = raycastClosestResult.hitNormal;
  51. const collider = raycastClosestResult.collider;
  52. const distance = raycastClosestResult.distance;
  53. console.log(collider.node.name);
  54. //当前其余点击无效
  55. if (collider.node.getComponent(Cube_Infor).state === Cube_State.live) {
  56. this.entryContainer(collider.node);
  57. }
  58. }
  59. console.log('发射了射线');
  60. }
  61. entryContainer(node: Node) {
  62. // 判断容器剩余容量
  63. let startIndex = -1;
  64. let targetPos = new Vec3();
  65. let txt_length = node.getComponent(Cube_Infor).Text.length;
  66. console.log(txt_length);
  67. // 判断字长 并 判断是否还有空间可放置
  68. switch (txt_length) {
  69. case 1:
  70. for (let i = 0; i < this.Container.node_isIdiom.length; i++) {
  71. if (this.Container.node_isIdiom[i] === false) {
  72. startIndex = i; // 找到连续的三个 false,记录起始位置
  73. break; // 找到第一个符合条件的位置后停止
  74. }
  75. }
  76. if (startIndex !== -1) { // 如果找到了一个值为 false 的元素
  77. targetPos = this.Container.nodes[startIndex].getWorldPosition().clone();
  78. this.Container.node_isIdiom[startIndex] = true;
  79. console.log(targetPos);
  80. } else {
  81. console.log("没有空间了");
  82. }
  83. break;
  84. case 2: {
  85. for (let i = 0; i < this.Container.node_isIdiom.length - 2; i++) {
  86. if (this.Container.node_isIdiom[i] === false &&
  87. this.Container.node_isIdiom[i + 1] === false) {
  88. startIndex = i; // 找到连续的两个 false,记录起始位置
  89. break; // 找到第一个符合条件的位置后停止
  90. }
  91. }
  92. if (startIndex !== -1) {
  93. console.log("找到连续的两个 false,起始索引是:", startIndex);
  94. // 可以在此使用 startIndex 进行后续操作,例如:
  95. let pos1 = this.Container.nodes[startIndex].getWorldPosition();
  96. let pos2 = this.Container.nodes[startIndex + 1].getWorldPosition();
  97. this.Container.node_isIdiom[startIndex] = true;
  98. this.Container.node_isIdiom[startIndex + 1] = true;
  99. targetPos.set(
  100. (pos1.x + pos2.x) / 2,
  101. (pos1.y + pos2.y) / 2,
  102. (pos1.z + pos2.z) / 2
  103. );
  104. console.log(targetPos);
  105. }
  106. break;
  107. }
  108. case 3: {
  109. for (let i = 0; i < this.Container.node_isIdiom.length - 2; i++) {
  110. if (this.Container.node_isIdiom[i] === false &&
  111. this.Container.node_isIdiom[i + 1] === false &&
  112. this.Container.node_isIdiom[i + 2] === false) {
  113. startIndex = i; // 找到连续的三个 false,记录起始位置
  114. break; // 找到第一个符合条件的位置后停止
  115. }
  116. }
  117. if (startIndex !== -1) {
  118. // 找到连续三个 false,startIndex 即为最前面的索引
  119. console.log("找到连续的三个 false,起始索引是:", startIndex);
  120. // 可以在此使用 startIndex 进行后续操作,例如:
  121. let pos1 = this.Container.nodes[startIndex].getWorldPosition();
  122. let pos2 = this.Container.nodes[startIndex + 1].getWorldPosition();
  123. let pos3 = this.Container.nodes[startIndex + 2].getWorldPosition();
  124. this.Container.node_isIdiom[startIndex] = true;
  125. this.Container.node_isIdiom[startIndex + 1] = true;
  126. this.Container.node_isIdiom[startIndex + 2] = true;
  127. targetPos.set(
  128. (pos1.x + pos2.x + pos3.x) / 3,
  129. (pos1.y + pos2.y + pos3.y) / 3,
  130. (pos1.z + pos2.z + pos3.z) / 3
  131. );
  132. console.log(targetPos);
  133. } else {
  134. console.log("没有找到连续的三个 false");
  135. }
  136. break;
  137. }
  138. default:
  139. return;
  140. }
  141. if (startIndex !== -1) {
  142. // node.getComponent(Cube_Infor).lock = true;
  143. node.getComponent(Cube_Infor).state = Cube_State.wait;
  144. node.getComponent(Cube_Infor).rigidbody.type = RigidBody.Type.STATIC; // 禁用重力
  145. let targetRotation = new Quat();
  146. Quat.fromEuler(targetRotation, -90, 0, 0);
  147. this.canTouch = false;
  148. tween(node)
  149. .to(0.5, { position: new Vec3(targetPos.x, targetPos.y, targetPos.z + 0.4), rotation: targetRotation })
  150. .call(() => {
  151. this.Container.idiom_combine.set(node.getComponent(Cube_Infor), startIndex);
  152. // 执行判断成语合成逻辑
  153. let matchedCubes: Cube_Infor[] = [];
  154. let flag = this.Container.checkIdiom_Combine(node.getComponent(Cube_Infor), matchedCubes);
  155. if (flag) {
  156. // 执行合成动画
  157. console.log("匹配的成语方块:", matchedCubes);
  158. this.combine_ani(matchedCubes[0], matchedCubes[1]);
  159. } else {
  160. //高亮
  161. gui.get(UI_Idioms).light_Show(node.getComponent(Cube_Infor));
  162. this.canTouch = true;
  163. }
  164. })
  165. .start();
  166. }
  167. }
  168. //合成动画
  169. combine_ani(cube1: Cube_Infor, cube2: Cube_Infor) {
  170. this.canTouch = true;
  171. for (let i = this.Container.idiom_combine.get(cube1); i < this.Container.idiom_combine.get(cube1) + cube1.Text.length; i++) {
  172. this.Container.node_isIdiom[i] = false;
  173. }
  174. this.Container.idiom_combine.delete(cube1);
  175. for (let i = this.Container.idiom_combine.get(cube2); i < this.Container.idiom_combine.get(cube2) + cube2.Text.length; i++) {
  176. this.Container.node_isIdiom[i] = false;
  177. }
  178. this.Container.idiom_combine.delete(cube2);
  179. // 取消相关字的高亮显示
  180. gui.get(UI_Idioms).light_Hide(cube1, cube2);
  181. gui.get(UI_Main).evt.emit(gui.get(UI_Main).evt.key.update_remain);
  182. this.adjustContainer();
  183. // 检测容器中哪些字需要高亮显示
  184. console.log(this.Container.node_isIdiom); // 在所有动画结束后执行
  185. this.Container.idioms = this.Container.idioms.filter(c => c.idiom !== cube1.Text + cube2.Text);
  186. // 创建第一个 tween 动画
  187. const tween1 = tween(cube1.node)
  188. .to(0.1, { position: new Vec3(this.Ani[0].position.x, this.Ani[0].position.y, this.Ani[0].position.z + 0.4) })
  189. .call(() => {
  190. setTimeout(() => {
  191. cube1.state = Cube_State.dead;
  192. this.Container.recycleCube(cube1.node);
  193. }, 500.0);
  194. });
  195. // 创建第二个 tween 动画
  196. const tween2 = tween(cube2.node)
  197. .to(0.1, { position: new Vec3(this.Ani[1].position.x, this.Ani[1].position.y, this.Ani[1].position.z + 0.4) })
  198. .call(() => {
  199. setTimeout(() => {
  200. cube2.state = Cube_State.dead;
  201. this.Container.recycleCube(cube2.node);
  202. }, 500.0);
  203. });
  204. // 使用 tween 的并行组合功能
  205. tween(cube1.node)
  206. .parallel(tween1, tween2) // 并行执行 tween1 和 tween2
  207. .call(()=>{
  208. Hall.getInstance().player.set_combine_num(1);
  209. })
  210. .start();
  211. }
  212. adjustContainer() {
  213. const container = this.Container;
  214. // 新的 node_isIdiom 状态数组
  215. const newNodeIsIdiom = Array(container.node_isIdiom.length).fill(false);
  216. // 新的 idiom_combine 映射表
  217. const newIdiomCombine = new Map<Cube_Infor, number>();
  218. // 遍历 idiom_combine,重新计算位置
  219. for (const [cube, startIndex] of container.idiom_combine.entries()) {
  220. const txtLength = cube.Text.length; // 获取字长
  221. let targetIndex = -1; // 目标位置起始索引
  222. let targetPos = new Vec3();
  223. switch (txtLength) {
  224. case 1: {
  225. // 找到一个空位
  226. for (let i = 0; i < container.node_isIdiom.length; i++) {
  227. if (!newNodeIsIdiom[i]) {
  228. targetIndex = i;
  229. break;
  230. }
  231. }
  232. if (targetIndex !== -1) {
  233. targetPos = container.nodes[targetIndex].getWorldPosition().clone();
  234. newNodeIsIdiom[targetIndex] = true; // 占用位置
  235. } else {
  236. console.log("没有空位容纳单字 Cube_Infor");
  237. }
  238. break;
  239. }
  240. case 2: {
  241. // 找到连续两个空位
  242. for (let i = 0; i < container.node_isIdiom.length - 1; i++) {
  243. if (!newNodeIsIdiom[i] && !newNodeIsIdiom[i + 1]) {
  244. targetIndex = i;
  245. break;
  246. }
  247. }
  248. if (targetIndex !== -1) {
  249. const pos1 = container.nodes[targetIndex].getWorldPosition();
  250. const pos2 = container.nodes[targetIndex + 1].getWorldPosition();
  251. targetPos.set(
  252. (pos1.x + pos2.x) / 2,
  253. (pos1.y + pos2.y) / 2,
  254. (pos1.z + pos2.z) / 2
  255. );
  256. newNodeIsIdiom[targetIndex] = true;
  257. newNodeIsIdiom[targetIndex + 1] = true;
  258. } else {
  259. console.log("没有连续两个空位容纳双字 Cube_Infor");
  260. }
  261. break;
  262. }
  263. case 3: {
  264. // 找到连续三个空位
  265. for (let i = 0; i < container.node_isIdiom.length - 2; i++) {
  266. if (
  267. !newNodeIsIdiom[i] &&
  268. !newNodeIsIdiom[i + 1] &&
  269. !newNodeIsIdiom[i + 2]
  270. ) {
  271. targetIndex = i;
  272. break;
  273. }
  274. }
  275. if (targetIndex !== -1) {
  276. const pos1 = container.nodes[targetIndex].getWorldPosition();
  277. const pos2 = container.nodes[targetIndex + 1].getWorldPosition();
  278. const pos3 = container.nodes[targetIndex + 2].getWorldPosition();
  279. targetPos.set(
  280. (pos1.x + pos2.x + pos3.x) / 3,
  281. (pos1.y + pos2.y + pos3.y) / 3,
  282. (pos1.z + pos2.z + pos3.z) / 3
  283. );
  284. newNodeIsIdiom[targetIndex] = true;
  285. newNodeIsIdiom[targetIndex + 1] = true;
  286. newNodeIsIdiom[targetIndex + 2] = true;
  287. } else {
  288. console.log("没有连续三个空位容纳三字 Cube_Infor");
  289. }
  290. break;
  291. }
  292. default:
  293. return;
  294. }
  295. // 移动 Cube_Infor 到目标位置
  296. if (targetIndex !== -1) {
  297. tween(cube.node)
  298. .to(0.3, { position: new Vec3(targetPos.x, targetPos.y, targetPos.z + 0.4) })
  299. .start();
  300. newIdiomCombine.set(cube, targetIndex); // 更新新映射
  301. }
  302. }
  303. // 更新 container 状态
  304. container.node_isIdiom = newNodeIsIdiom;
  305. container.idiom_combine = newIdiomCombine;
  306. console.log("调整后的容器状态:", container.node_isIdiom);
  307. console.log("更新后的 idiom_combine:", [...container.idiom_combine.entries()]);
  308. }
  309. }