Container_Manager.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. import { _decorator, BoxCollider, Component, find, instantiate, Node, NodePool, Prefab, Quat, random, RigidBody, tween, Vec3 } from 'cc';
  2. import ch_util from '../../ch/ch_util';
  3. import { gui } from '../../core/ui/ui';
  4. import { table_idiom } from '../../module_extra/table_ts/table_idiom';
  5. import { table_level } from '../../module_extra/table_ts/table_level';
  6. import { Hall } from '../hall/Hall';
  7. import { UI_Idioms } from '../ui/UI_Idioms/UI_Idioms';
  8. import { UI_Main } from '../ui/UI_Main/UI_Main';
  9. import { CreateIdiom } from './CreateIdiom';
  10. import { Cube_Infor, Cube_State } from './Cube_Infor';
  11. import { GameCtl } from './GameCtl';
  12. import { ch } from '../../ch/ch';
  13. import { Layout_Main } from '../ui/UI_Main/Layout_Main';
  14. import { table_idiom_order } from '../../module_extra/table_ts/table_idiom_order';
  15. import { table_idiom_unorder_1_3 } from '../../module_extra/table_ts/table_idiom_unorder_1_3';
  16. import { table_idiom_unorder_2_2 } from '../../module_extra/table_ts/table_idiom_unorder_2_2';
  17. import { table_idiom_unorder_3_1 } from '../../module_extra/table_ts/table_idiom_unorder_3_1';
  18. import { table_level_2 } from '../../module_extra/table_ts/table_level_2';
  19. import ArrayUtil from '../../core/util/ArrayUtil';
  20. const { ccclass, property } = _decorator;
  21. @ccclass('Container_Manager')
  22. export class Container_Manager extends Component {
  23. canTouch: boolean = false;
  24. @property([Node])
  25. Lock_node: Node[] = [];
  26. @property([Prefab])
  27. prefabs: Prefab[] = [];
  28. level_config: any = null;//关卡配置
  29. level2_config: any = null;//第二关配置
  30. config: any = null;//有规律的成语库
  31. config_1_3: any = null;//无规律1+3
  32. config_2_2: any = null;//无规律2+2
  33. config_3_1: any = null;//无规律3+1
  34. idioms: any[] = [];//生成的成语
  35. index: number[] = [];//生成的成语角标,避免生成重复成语
  36. @property(CreateIdiom)
  37. create_node: CreateIdiom = null;
  38. @property([Node])
  39. nodes: Node[] = [];//位置节点 用于成语放入
  40. node_isIdiom: boolean[] = new Array(9).fill(false);
  41. unlock_Num: number = 7;
  42. is_Show_UI_Lock = false;
  43. idiom_combine: Map<Cube_Infor, number> = new Map();
  44. Cube_Pool: NodePool = new NodePool();
  45. nodeReferences: Node[] = []; // 额外维护的节点引用数组
  46. count: number = 0;
  47. private instantiateCube() {
  48. for (let i = 0; i < this.idioms.length * 2; i++) {
  49. let idiomIndex = Math.floor(i / 2);
  50. let isPiece1 = i % 2 === 0;
  51. let Text_Length = isPiece1
  52. ? this.idioms[idiomIndex].piece_1_word.length
  53. : this.idioms[idiomIndex].piece_2_word.length;
  54. const newCube = instantiate(this.prefabs[Text_Length - 1]);
  55. newCube.active = true; // 初始时设置为非激活状态
  56. // 按顺序为节点赋值文字内容
  57. newCube.getComponent(Cube_Infor).Text = isPiece1
  58. ? this.idioms[idiomIndex].piece_1_word
  59. : this.idioms[idiomIndex].piece_2_word;
  60. console.log("生成第" + i + "个节点:" + newCube.getComponent(Cube_Infor).Text);
  61. this.Cube_Pool.put(newCube);
  62. }
  63. this.shufflePool();
  64. }
  65. public getCube(): Node {
  66. console.log(this.Cube_Pool.size());
  67. const cube = this.Cube_Pool.get();
  68. if (cube)
  69. cube.active = true;
  70. return cube;
  71. }
  72. // 将方块回收到对象池
  73. public recycleCube(cube: Node): void {
  74. cube.active = false; // 将方块设置为非激活状态
  75. this.Cube_Pool.put(cube);
  76. }
  77. //清空对象池
  78. public clearCubePool() {
  79. this.Cube_Pool.clear();
  80. }
  81. //合成规则导入
  82. start() {
  83. this.config = table_idiom_order.getList();
  84. this.config_1_3 = table_idiom_unorder_1_3.getList();
  85. this.config_2_2 = table_idiom_unorder_2_2.getList();
  86. this.config_3_1 = table_idiom_unorder_3_1.getList();
  87. console.log(this.config.length);
  88. console.log(this.config_1_3.length);
  89. console.log(this.config_2_2.length);
  90. console.log(this.config_3_1.length);
  91. this.level_config = table_level.getList();
  92. this.level2_config = table_level_2.getList();
  93. // if (this.level_config.length === 5) {
  94. // console.log("关卡配置导入成功");
  95. // }
  96. this.level_idioms();
  97. }
  98. update(deltaTime: number) {
  99. }
  100. checkIdiom_Combine(matchedcube2: Cube_Infor, outMatchedCubes: Cube_Infor[]): boolean {
  101. if (this.idiom_combine.size < 2) {
  102. return false; // 至少需要两个方块
  103. }
  104. for (let cube of this.idiom_combine.keys()) {
  105. // 遍历 idioms 列表,检查是否匹配成语
  106. const matchedIdiom = this.idioms.find(
  107. idiom =>
  108. idiom.piece_1_word === cube.Text && idiom.piece_2_word === matchedcube2.Text
  109. );
  110. if (matchedIdiom) {
  111. // 匹配成功
  112. outMatchedCubes.push(cube, matchedcube2);
  113. this.nodeReferences = this.nodeReferences.filter((el) => el !== matchedcube2.node && el !== cube.node);
  114. console.log("成功拼成成语: " + matchedIdiom.piece_1_word + matchedIdiom.piece_2_word);
  115. return true;
  116. }
  117. // 再检查逆序组合是否匹配
  118. const reverseMatchedIdiom = this.idioms.find(
  119. idiom =>
  120. idiom.piece_1_word === matchedcube2.Text && idiom.piece_2_word === cube.Text
  121. );
  122. if (reverseMatchedIdiom) {
  123. // 匹配成功
  124. outMatchedCubes.push(matchedcube2, cube);
  125. this.nodeReferences = this.nodeReferences.filter((el) => el !== matchedcube2.node && el !== cube.node);
  126. console.log(
  127. "成功拼成成语: " +
  128. reverseMatchedIdiom.piece_1_word +
  129. reverseMatchedIdiom.piece_2_word
  130. );
  131. return true;
  132. }
  133. }
  134. return false; // 没有匹配到成语
  135. }
  136. async level_idioms() {
  137. this.Lock_node.forEach(node => {
  138. node.active = true;
  139. });
  140. this.unlock_Num = 7;
  141. this.is_Show_UI_Lock = false;
  142. this.canTouch = false;
  143. let level = Hall.getInstance().player.get_max_floor();
  144. for(let i = 0;i<this.nodeReferences.length;i++){
  145. if(this.nodeReferences[i])
  146. this.nodeReferences[i].destroy();
  147. }
  148. this.clearCubePool();
  149. this.idioms = [];
  150. this.nodeReferences=[];
  151. this.node_isIdiom=new Array(9).fill(false);
  152. this.idiom_combine=new Map();
  153. // if (level === 0) {
  154. // let str2: string = this.level_config[level].idiom_type_2;
  155. // let idiom_type_2 = str2.split("_");
  156. // console.log("idiom_type_2:", idiom_type_2);
  157. // let selectedIdioms: Record<string, any[]> = {};
  158. // [...idiom_type_2].forEach(rule => {
  159. // let filteredIdioms = this.config.filter(item => item.piece_2_word === rule);
  160. // if (filteredIdioms.length === 0) {
  161. // filteredIdioms = this.config_2_2.filter(item => item.piece_2_word === rule);
  162. // }
  163. // console.log(`筛选2 ${rule} 后的成语:`, filteredIdioms);
  164. // selectedIdioms[rule] = filteredIdioms;
  165. // });
  166. // for (let rule in selectedIdioms) {
  167. // if (selectedIdioms.hasOwnProperty(rule)) {
  168. // this.idioms.push(...selectedIdioms[rule]);
  169. // }
  170. // }
  171. // console.log("最终选中的成语:", this.idioms);
  172. // } else if (level === 1) {
  173. // for (let i = 0; i < 30; i++) {
  174. // let filteredIdiom = this.config.filter(item => item.idiom == this.level2_config[i].idiom);
  175. // this.idioms.push(...filteredIdiom);
  176. // }
  177. // for (let i = 30; i < 40; i++) {
  178. // let filteredIdiom = this.config_2_2.filter(item => item.idiom == this.level2_config[i].idiom);
  179. // this.idioms.push(...filteredIdiom);
  180. // }
  181. // }
  182. {
  183. // 获取当前层级的筛选条件
  184. if(level==0||level==1)
  185. {
  186. level=2;
  187. }
  188. let str1: string = this.level_config[level].idiom_type_1;
  189. let idiom_type_1 = str1.split("_"); // 分割成数组
  190. console.log("idiom_type_1:", idiom_type_1);
  191. let str2: string = this.level_config[level].idiom_type_2;
  192. let idiom_type_2 = str2.split("_"); // 分割成数组
  193. console.log("idiom_type_2:", idiom_type_2);
  194. let count = this.level_config[level].count / (idiom_type_1.length + idiom_type_2.length);
  195. // 初始化保存结果的数组
  196. let selectedIdioms: Record<string, any[]> = {};
  197. // 遍历 idiom_type_1的每个规律
  198. [...idiom_type_1].forEach(rule => {
  199. // 从 config 中筛选符合当前规律的成语
  200. let filteredIdioms = this.config.filter(item => item.piece_1_word === rule);
  201. console.log(`筛选 ${rule} 后的成语:`, filteredIdioms);
  202. if (filteredIdioms.length < count) {
  203. console.error(`规律 ${rule} 的成语数量不足,仅有 ${filteredIdioms.length} 个`);
  204. } else {
  205. console.log(`规律 ${rule} 的成语数量:${filteredIdioms.length}`);
  206. let selected = [];
  207. // 随机选择不重复的成语
  208. for (let i = 0; i < count;) {
  209. let rand = ch_util.getRandomInt(0, filteredIdioms.length - 1); // 确保 rand 在有效范围内
  210. let selectedIdiom = filteredIdioms[rand];
  211. // 从数组中移除已选成语,避免再次选择
  212. filteredIdioms.splice(rand, 1);
  213. // 添加到已选数组中
  214. selected.push(selectedIdiom);
  215. console.log(`选中的成语:${selectedIdiom.idiom}`);
  216. i++;
  217. }
  218. selectedIdioms[rule] = selected;
  219. }
  220. });
  221. // 遍历idiom_type_2 的每个规律
  222. [...idiom_type_2].forEach(rule => {
  223. // 从 config 中筛选符合当前规律的成语
  224. let filteredIdioms = this.config.filter(item => item.piece_2_word === rule);
  225. console.log(`筛选2 ${rule} 后的成语:`, filteredIdioms);
  226. if (filteredIdioms.length < count) {
  227. console.error(`规律2 ${rule} 的成语数量不足,仅有 ${filteredIdioms.length} 个`);
  228. } else {
  229. console.log(`规律2 ${rule} 的成语数量:${filteredIdioms.length}`);
  230. let selected = [];
  231. // 随机选择不重复的成语
  232. for (let i = 0; i < count;) {
  233. let rand = ch_util.getRandomInt(0, filteredIdioms.length - 1); // 确保 rand 在有效范围内
  234. let selectedIdiom = filteredIdioms[rand];
  235. // 从数组中移除已选成语,避免再次选择
  236. filteredIdioms.splice(rand, 1);
  237. // 添加到已选数组中
  238. selected.push(selectedIdiom);
  239. console.log(`选中的成语:${selectedIdiom.idiom}`);
  240. i++;
  241. }
  242. selectedIdioms[rule] = selected;
  243. }
  244. });
  245. // 将所有选中的成语合并到 idioms 数组
  246. for (let rule in selectedIdioms) {
  247. if (selectedIdioms.hasOwnProperty(rule)) {
  248. this.idioms.push(...selectedIdioms[rule]); // 使用扩展运算符合并成语
  249. }
  250. }
  251. //
  252. if (this.level_config[level].easy_1_3 > 0) {
  253. let filteredIdioms = this.config_1_3.filter(item => item.difficulty === "easy");
  254. for (let i = 0; i < this.level_config[level].easy_1_3; i++) {
  255. let rand = ch_util.getRandomInt(0, filteredIdioms.length - 1);
  256. let selectedIdiom = filteredIdioms[rand];
  257. filteredIdioms.splice(rand, 1);
  258. this.idioms.push(selectedIdiom);
  259. }
  260. }
  261. if (this.level_config[level].hard_1_3 > 0) {
  262. let filteredIdioms = this.config_1_3.filter(item => item.difficulty === "hard");
  263. for (let i = 0; i < this.level_config[level].hard_1_3; i++) {
  264. let rand = ch_util.getRandomInt(0, filteredIdioms.length - 1);
  265. let selectedIdiom = filteredIdioms[rand];
  266. filteredIdioms.splice(rand, 1);
  267. this.idioms.push(selectedIdiom);
  268. }
  269. }
  270. if (this.level_config[level].easy_2_2 > 0) {
  271. let filteredIdioms = this.config_2_2.filter(item => item.difficulty === "easy");
  272. for (let i = 0; i < this.level_config[level].easy_2_2; i++) {
  273. let rand = ch_util.getRandomInt(0, filteredIdioms.length - 1);
  274. let selectedIdiom = filteredIdioms[rand];
  275. filteredIdioms.splice(rand, 1);
  276. this.idioms.push(selectedIdiom);
  277. }
  278. }
  279. if (this.level_config[level].hard_2_2 > 0) {
  280. let filteredIdioms = this.config_2_2.filter(item => item.difficulty === "hard");
  281. for (let i = 0; i < this.level_config[level].hard_2_2; i++) {
  282. let rand = ch_util.getRandomInt(0, filteredIdioms.length - 1);
  283. let selectedIdiom = filteredIdioms[rand];
  284. filteredIdioms.splice(rand, 1);
  285. this.idioms.push(selectedIdiom);
  286. }
  287. }
  288. if (this.level_config[level].easy_3_1 > 0) {
  289. let filteredIdioms = this.config_3_1.filter(item => item.difficulty === "easy");
  290. for (let i = 0; i < this.level_config[level].easy_3_1; i++) {
  291. let rand = ch_util.getRandomInt(0, filteredIdioms.length - 1);
  292. let selectedIdiom = filteredIdioms[rand];
  293. filteredIdioms.splice(rand, 1);
  294. this.idioms.push(selectedIdiom);
  295. }
  296. }
  297. if (this.level_config[level].hard_1_3 > 0) {
  298. let filteredIdioms = this.config_1_3.filter(item => item.difficulty === "hard");
  299. for (let i = 0; i < this.level_config[level].hard_1_3; i++) {
  300. let rand = ch_util.getRandomInt(0, filteredIdioms.length - 1);
  301. let selectedIdiom = filteredIdioms[rand];
  302. filteredIdioms.splice(rand, 1);
  303. this.idioms.push(selectedIdiom);
  304. }
  305. }
  306. console.log("最终选中的成语:", this.idioms); // 打印最终的成语数组
  307. }
  308. this.count = this.level_config[level].total;
  309. await this.instantiateCube();
  310. await gui.show(UI_Idioms);
  311. await this.create_node.nodeMoving();
  312. gui.show(UI_Main);
  313. }
  314. //消除一组
  315. eliminate() {
  316. //先判断槽内是否有方块,如果有,匹配槽内最前面一个与散落方块中的
  317. let cube;
  318. for (const [key, value] of this.idiom_combine) {
  319. if (value === 0) {
  320. cube = key;
  321. break;
  322. }
  323. }
  324. //槽中有方块
  325. if (cube) {
  326. const originalReferences = [...this.nodeReferences];
  327. for (const element of originalReferences) {
  328. if (this.idioms.find(c => c.idiom == element.getComponent(Cube_Infor).Text + cube.Text) && element.getComponent(Cube_Infor) !== cube) {
  329. console.log(element.getComponent(Cube_Infor).Text);
  330. element.getComponent(Cube_Infor).state = Cube_State.wait;
  331. element.getComponent(Cube_Infor).rigidbody.type = RigidBody.Type.STATIC;
  332. element.getComponent(BoxCollider).enabled = false;
  333. let targetRotation = new Quat();
  334. Quat.fromEuler(targetRotation, -90, 0, 0);
  335. element.rotation = targetRotation;
  336. // 使用filter过滤掉当前元素
  337. GameCtl.instance.combine_ani(element.getComponent(Cube_Infor), cube);
  338. this.nodeReferences = this.nodeReferences.filter((el) => el !== element && el !== cube.node);
  339. break;
  340. }
  341. else if (this.idioms.find(c => c.idiom == cube.Text + element.getComponent(Cube_Infor).Text) && element.getComponent(Cube_Infor) !== cube) {
  342. console.log(element.getComponent(Cube_Infor).Text);
  343. element.getComponent(Cube_Infor).state = Cube_State.wait;
  344. element.getComponent(Cube_Infor).rigidbody.type = RigidBody.Type.STATIC;
  345. element.getComponent(BoxCollider).enabled = false;
  346. let targetRotation = new Quat();
  347. Quat.fromEuler(targetRotation, -90, 0, 0);
  348. element.rotation = targetRotation;
  349. GameCtl.instance.combine_ani(cube, element.getComponent(Cube_Infor));
  350. this.nodeReferences = this.nodeReferences.filter((el) => el !== element && el !== cube.node);
  351. break;
  352. }
  353. }
  354. }
  355. //槽中没有方块
  356. else {
  357. let flag: boolean = false;
  358. const originalReferences1 = [...this.nodeReferences];
  359. const originalReferences2 = [...this.nodeReferences];
  360. for (const element1 of originalReferences1) {
  361. for (const element2 of originalReferences2) {
  362. if (this.idioms.find(c => c.idiom == element1.getComponent(Cube_Infor).Text + element2.getComponent(Cube_Infor).Text)) {
  363. element1.getComponent(Cube_Infor).state = Cube_State.wait;
  364. element1.getComponent(Cube_Infor).rigidbody.type = RigidBody.Type.STATIC;
  365. let targetRotation = new Quat();
  366. Quat.fromEuler(targetRotation, -90, 0, 0);
  367. element1.rotation = targetRotation;
  368. element2.getComponent(Cube_Infor).state = Cube_State.wait;
  369. element2.getComponent(Cube_Infor).rigidbody.type = RigidBody.Type.STATIC;
  370. element2.getComponent(BoxCollider).enabled = false;
  371. element2.rotation = targetRotation;
  372. // 使用filter过滤掉当前元素
  373. GameCtl.instance.combine_ani(element1.getComponent(Cube_Infor), element2.getComponent(Cube_Infor));
  374. this.nodeReferences = this.nodeReferences.filter((el) => el !== element1 && el !== element2);
  375. flag = true;
  376. break;
  377. }
  378. if (this.idioms.find(c => c.idiom == element2.getComponent(Cube_Infor).Text + element1.getComponent(Cube_Infor).Text)) {
  379. element1.getComponent(Cube_Infor).state = Cube_State.wait;
  380. element1.getComponent(Cube_Infor).rigidbody.type = RigidBody.Type.STATIC;
  381. let targetRotation = new Quat();
  382. Quat.fromEuler(targetRotation, -90, 0, 0);
  383. element1.rotation = targetRotation;
  384. element2.getComponent(Cube_Infor).state = Cube_State.wait;
  385. element2.getComponent(Cube_Infor).rigidbody.type = RigidBody.Type.STATIC;
  386. element2.getComponent(BoxCollider).enabled = false;
  387. element2.rotation = targetRotation;
  388. // 使用filter过滤掉当前元素
  389. GameCtl.instance.combine_ani(element2.getComponent(Cube_Infor), element1.getComponent(Cube_Infor));
  390. this.nodeReferences = this.nodeReferences.filter((el) => el !== element1 && el !== element2);
  391. flag = true;
  392. break;
  393. }
  394. }
  395. if (flag === true) {
  396. break;
  397. }
  398. }
  399. }
  400. }
  401. async shuffle() {
  402. // 回收所有非槽内的活跃节点
  403. this.nodeReferences.forEach(node => {
  404. const cubeInfo = node.getComponent(Cube_Infor);
  405. if (cubeInfo.state === Cube_State.live) {
  406. let targetRotation = new Quat();
  407. Quat.fromEuler(targetRotation, -90, 0, 0);
  408. node.rotation = targetRotation;
  409. this.recycleCube(node); // 回收到池中
  410. }
  411. });
  412. this.shufflePool();
  413. // 等待节点移动完成后执行后续逻辑
  414. await this.create_node.nodeMoving();
  415. }
  416. //清空槽子
  417. Empty() {
  418. for (let idiom of this.idiom_combine.keys()) {
  419. idiom.state = Cube_State.live;
  420. let posX = ch.util.getRandom(-3, 3);
  421. let posZ = ch.util.getRandom(-3, 3);
  422. tween(idiom.node).to(0.5, { position: new Vec3(posX, this.create_node.node.position.y + 5, posZ) }).call(() => {
  423. idiom.rigidbody.type = RigidBody.Type.DYNAMIC;
  424. }).start();
  425. //idiom.node.position = ;
  426. }
  427. this.idiom_combine.clear();
  428. this.node_isIdiom.fill(false);
  429. gui.get(UI_Idioms).all_light_Hide();
  430. }
  431. AddTime() {
  432. const layout = gui.get(UI_Main).getLayout<Layout_Main>();
  433. layout.time += 120;
  434. }
  435. private shufflePool() {
  436. const poolSize = this.Cube_Pool.size();
  437. const tempArray = [];
  438. // 从池中取出所有节点到临时数组
  439. for (let i = 0; i < poolSize; i++) {
  440. tempArray.push(this.Cube_Pool.get());
  441. }
  442. // 只打乱部分节点(以 50% 为例,可调整比例)
  443. const shuffleCount = Math.ceil(poolSize * 0.5); // 只打乱前 50%
  444. for (let i = 0; i < shuffleCount; i++) {
  445. const randomIndex = Math.floor(Math.random() * poolSize);
  446. [tempArray[i], tempArray[randomIndex]] = [tempArray[randomIndex], tempArray[i]];
  447. }
  448. // 将打乱的节点放回池中
  449. tempArray.forEach(cube => this.Cube_Pool.put(cube));
  450. }
  451. }