GameLink.ts 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. import { _decorator, Component, math, Node } from 'cc';
  2. import { Game } from '../../core/util_comp/Game';
  3. import { ch } from '../../ch/ch';
  4. import TableLoadUtil from '../../core/util/TableLoadUtil';
  5. import { ModuleDef } from '../../scripts/ModuleDef';
  6. import { TableUtil } from '../../module_extra/table_ts/TableUtil';
  7. import map from './Map';
  8. import Block, { BlockState } from './block/block';
  9. import { FMSType } from '../process/FMS';
  10. import { Link } from './Link';
  11. import { Lv, LvDir } from './Lv';
  12. import { UINotify } from '../../module_basic/ui_notify/UINotify';
  13. import player, { data_type, day_data_type, rand_type, week_data_type } from './Player';
  14. import get_new_head_icon from '../../core/util_class/HeadIcon';
  15. import { gui } from '../../core/ui/ui';
  16. interface event_protocol {
  17. show_path(path: { x: number, y: number }[]): void;
  18. game_start(): void;
  19. game_wait(): void;
  20. game_end(win: boolean): void;
  21. show_block_type(id: number, type: number): void;
  22. }
  23. export enum GameState {
  24. init = 0,
  25. wait = 1,
  26. match = 2,
  27. end = 3,
  28. move = 4,
  29. }
  30. const { ccclass, property } = _decorator;
  31. @ccclass('GameLink')
  32. export class GameLink extends Game<GameLink> {
  33. //
  34. private _bs: Map<number, Block> = new Map();
  35. public map: map = new map();
  36. public link: Link;
  37. public lv: Lv;
  38. public player: player;
  39. public head_icon = get_new_head_icon();
  40. public evt = ch.get_new_event<event_protocol>();
  41. public state: GameState = GameState.init;
  42. public ver_b: boolean = false;
  43. public vibrate: boolean = false;
  44. onLoad(): void {
  45. super.onLoad();
  46. this.vibrate = ch.storage.getBoolean('linkup_vibrate');
  47. // console.log(new Date(chsdk.date.now()));
  48. }
  49. public set_vibrate(b: boolean): void {
  50. this.vibrate = b;
  51. if (this.vibrate) {
  52. ch.storage.set('linkup_vibrate', 1);
  53. } else {
  54. ch.storage.remove('linkup_vibrate');
  55. }
  56. }
  57. public vibrateShort(): void {
  58. if (!this.vibrate) return;
  59. ch.sdk.vibrateShort();
  60. }
  61. public vibrateLong(): void {
  62. if (!this.vibrate) return;
  63. ch.sdk.vibrateLong();
  64. }
  65. update(deltaTime: number) {
  66. super.update(deltaTime);
  67. if (this.is_paused) return;
  68. const list = Array.from(this._bs.values());
  69. for (let i = 0; i < list.length; i++) {
  70. list[i].action(deltaTime);
  71. }
  72. if (this.state != GameState.wait) return;
  73. this.lv?.time_run(deltaTime);
  74. }
  75. async start() {
  76. this.loadTable();
  77. this.player = player.getInstance(ch.sdk.get_gid(), ch.sdk.get_uid().toString());
  78. this.player.init_user_info();
  79. this.link = new Link(this.map);
  80. this.lv = new Lv();
  81. await this.player.load();
  82. if (chsdk.checkFromSidebar() && this.player.get_is_favorite() == 0) {
  83. this.player.add_item(3, 1);//提示道具
  84. this.player.set_is_favorite();
  85. }
  86. if (this.player.get_bx_time() < 0) {
  87. this.player.set_bx_time(300);
  88. }
  89. GameLink.getInst().to_main();
  90. }
  91. to_main() {
  92. this.FMS.Change(FMSType.Main);
  93. }
  94. private _ch_lv: number | null;
  95. to_start(lv?: number | null) {
  96. this._ch_lv = lv;
  97. this.FMS.Change(FMSType.Start);
  98. }
  99. async game_start() {
  100. //this.resume();
  101. this.game_clear();
  102. this.player.set_item(1, 4);
  103. const floor = this.player.data.get(data_type.max_floor);
  104. const lv = this._ch_lv ?? this.player.day_data.get(day_data_type.lv);
  105. this._ch_lv = null;
  106. this.lv.init(floor <= 0 ? 1 : floor, lv <= 0 ? 1 : lv);
  107. ch.log.debug('开始关卡', floor, lv, this.lv.seed);
  108. this.ranodm.set_seed(this.lv.seed);
  109. if (this.lv.lv == 1) {
  110. this.random_novice();
  111. } else {
  112. this.random_all_map(10 - this.lv.lv);
  113. }
  114. //
  115. this.evt.emit(this.evt.key.game_start);
  116. //await this.delay.start(3);
  117. //this.lv.win();
  118. }
  119. async game_end() {
  120. if (this.loop_id) this.job.DeleteTimeTask(this.loop_id);
  121. this.loop_id = null;
  122. this.state = GameState.end;
  123. await this.delay.start(0.3);
  124. //this.pause();
  125. if (this.lv.is_win) {
  126. //连胜下标变换的判断
  127. this.player.set_ls(1);//连胜+1
  128. let res = GameLink.getInst().player.get_ls_index();
  129. //更新最大连胜下标
  130. let index = GameLink.getInst().player.get_max_ls_index();
  131. console.log('当前连胜下标' + res);
  132. console.log('当前最大连胜下标' + index);
  133. //GameLink.getInst().player.config[index]
  134. if (res >= index + 1) {
  135. GameLink.getInst().player.set_lsbx_redpoint(1);
  136. GameLink.getInst().player.set_max_ls_index(1);
  137. console.log('更新最大连胜下标' + GameLink.getInst().player.get_max_ls_index());
  138. }
  139. if (this.lv.lv == 10) {
  140. this.player.data.add(data_type.max_floor, 1);
  141. this.player.data.add(data_type.floor, 1);
  142. this.player.day_data.set(day_data_type.lv, 1);
  143. this.player.save_rank_floor();
  144. this.player.setDirty();
  145. this.player.save();
  146. } else {
  147. this.player.day_data.add(day_data_type.lv, 1);
  148. this.player.setDirty();
  149. }
  150. this.player.day_data.add(day_data_type.total_lv, 1);
  151. this.player.save_rank_total_lv();
  152. } else {
  153. this.player.week_data.set(week_data_type.ls, 0);//重置连胜
  154. this.player.day_data.add(day_data_type.try, 1);
  155. this.player.setDirty();
  156. }
  157. this.evt.emit(this.evt.key.game_end, this.lv.is_win);
  158. }
  159. async relife() {
  160. this.player.day_data.sub(day_data_type.try, -1);
  161. this.lv.relife();
  162. await this.delay.start(0.5);
  163. this.state = GameState.wait;
  164. this.resume();
  165. }
  166. game_clear(): void {
  167. this.removeAllBlock();
  168. this.map.dispose();
  169. this._bs.clear();
  170. this._choose_id_a = null;
  171. this._choose_id_b = null;
  172. }
  173. /**随机新手关*/
  174. private random_novice(): void {
  175. const x: number = 10;
  176. const y: number = 16;
  177. const max: number = 10;
  178. const type_count: number = 27;
  179. this.map.init(x, y);
  180. const by = this.ranodm.int(6, 8);
  181. const t = this.ranodm.int(0, type_count);
  182. const b1 = this.creatBlock(t);
  183. b1.SetCell(4, by);
  184. const b2 = this.creatBlock(t);
  185. b2.SetCell(5, by);
  186. const values: number[] = [];
  187. for (let i = 0; i < max; i += 2) {
  188. const t = this.ranodm.int(0, type_count);
  189. values.push(t);
  190. values.push(t);
  191. }
  192. for (let i = values.length - 1; i > 0; i--) {
  193. const j = this.ranodm.int(0, i + 1);
  194. [values[i], values[j]] = [values[j], values[i]];
  195. }
  196. const x_list = [2, 4, 5, 7];
  197. const y_list = [6, 7, 9];
  198. let n: number = 0;
  199. for (let i = 0; i < x_list.length; i++) {
  200. for (let j = 0; j < y_list.length; j++) {
  201. if (y_list[j] == by && (x_list[i] == 4 || x_list[i] == 5)) continue;
  202. const b = this.creatBlock(values[n]);
  203. b.SetCell(x_list[i], y_list[j]);
  204. n++;
  205. }
  206. }
  207. }
  208. /**随机整个地图方块,至少保证有几对连在一起*/
  209. private random_all_map(pairsToAdd: number): void {
  210. pairsToAdd = pairsToAdd <= 0 ? 0 : pairsToAdd;
  211. const x: number = 10;
  212. const y: number = 16;
  213. const max: number = ((x - 2) * (y - 2));
  214. const type_count: number = 27;
  215. this.map.init(x, y);
  216. //
  217. const types = Array.from({ length: type_count }, (_, i) => i);
  218. let values: number[] = [];
  219. for (let i = 0; i < types.length; i++) {
  220. const t = types[i];
  221. values.push(t);
  222. values.push(t);
  223. }
  224. for (let i = values.length; i < max; i += 2) {
  225. const t = this.ranodm.int(0, type_count);
  226. values.push(t);
  227. values.push(t);
  228. }
  229. let placedPairs = 0;
  230. while (placedPairs < pairsToAdd) {
  231. const row_a = this.ranodm.int(1, x - 1);
  232. const col_a = this.ranodm.int(1, y - 1);
  233. if (this.map.check_empty(row_a, col_a, 1)) {
  234. let row_b = row_a;
  235. let col_b = col_a;
  236. if (this.ranodm.dir() > 0) {
  237. row_b += this.ranodm.dir();
  238. } else {
  239. col_b += this.ranodm.dir();
  240. }
  241. if (this.map.check_empty(row_b, col_b, 1)) {
  242. const a = this.creatBlock(values[placedPairs * 2]);
  243. a.SetCell(row_a, col_a);
  244. const b = this.creatBlock(values[placedPairs * 2 + 1]);
  245. b.SetCell(row_b, col_b);
  246. placedPairs++;
  247. }
  248. }
  249. }
  250. values = values.slice(pairsToAdd * 2);
  251. for (let i = values.length - 1; i > 0; i--) {
  252. const j = this.ranodm.int(0, i + 1);
  253. [values[i], values[j]] = [values[j], values[i]];
  254. }
  255. let n: number = 0;
  256. for (let row = 1; row < x - 1; row++) {
  257. for (let col = 1; col < y - 1; col++) {
  258. if (this.map.check_empty(row, col)) {
  259. const b = this.creatBlock(values[n]);
  260. b.SetCell(row, col);
  261. n++;
  262. }
  263. }
  264. }
  265. //ch.log.debug(this.map);
  266. }
  267. //
  268. public async blockShowUp() {
  269. const k = 0.01;
  270. let c: number = 0;
  271. if (this.lv.dir == LvDir.none) {
  272. let values = this.getAllBlock();
  273. for (let i = values.length - 1; i > 0; i--) {
  274. const j = this.ranodm.int(0, i + 1);
  275. [values[i], values[j]] = [values[j], values[i]];
  276. }
  277. for (let i = 0; i < values.length; i += 2) {
  278. values[i].setState(BlockState.show);
  279. values[i + 1].setState(BlockState.show);
  280. await this.delay.start(k);
  281. c += k;
  282. }
  283. } else if (this.lv.dir == LvDir.xCenter) {
  284. const midRow = Math.floor(this.map.rows * 0.5);
  285. for (let offset = midRow - 1; offset >= 0; offset--) {
  286. for (let col = 1; col < this.map.cols - 1; col++) {
  287. const ida = this.map.get_id(midRow + offset, col);
  288. if (!ida) continue;
  289. this.getBlock(ida)?.setState(BlockState.show);
  290. const idb = this.map.get_id(midRow - offset - 1, col);
  291. if (!idb) continue;
  292. this.getBlock(idb)?.setState(BlockState.show);
  293. await this.delay.start(k);
  294. c += k;
  295. }
  296. }
  297. } else if (this.lv.dir == LvDir.xOut) {
  298. const midRow = Math.floor(this.map.rows * 0.5);
  299. for (let offset = 0; offset < midRow; offset++) {
  300. for (let col = 1; col < this.map.cols - 1; col++) {
  301. const ida = this.map.get_id(midRow + offset, col);
  302. if (!ida) continue;
  303. this.getBlock(ida)?.setState(BlockState.show);
  304. const idb = this.map.get_id(midRow - offset - 1, col);
  305. if (!idb) continue;
  306. this.getBlock(idb)?.setState(BlockState.show);
  307. await this.delay.start(k);
  308. c += k;
  309. }
  310. }
  311. } else if (this.lv.dir == LvDir.yCenter) {
  312. const midCol = Math.floor(this.map.cols * 0.5);
  313. for (let offset = midCol - 1; offset >= 0; offset--) {
  314. for (let row = 1; row < this.map.rows - 1; row++) {
  315. const ida = this.map.get_id(row, midCol + offset);
  316. if (!ida) continue;
  317. this.getBlock(ida)?.setState(BlockState.show);
  318. const idb = this.map.get_id(row, midCol - offset - 1);
  319. if (!idb) continue;
  320. this.getBlock(idb)?.setState(BlockState.show);
  321. await this.delay.start(k);
  322. c += k;
  323. }
  324. }
  325. } else if (this.lv.dir == LvDir.yOut) {
  326. const midCol = Math.floor(this.map.cols * 0.5);
  327. for (let offset = 0; offset < midCol; offset++) {
  328. for (let row = 1; row < this.map.rows - 1; row++) {
  329. const ida = this.map.get_id(row, midCol + offset);
  330. if (!ida) continue;
  331. this.getBlock(ida)?.setState(BlockState.show);
  332. const idb = this.map.get_id(row, midCol - offset - 1);
  333. if (!idb) continue;
  334. this.getBlock(idb)?.setState(BlockState.show);
  335. await this.delay.start(k);
  336. c += k;
  337. }
  338. }
  339. } else if (this.lv.dir == LvDir.up) {
  340. //向上
  341. for (let col = this.map.cols - 2; col >= 1; col--) {
  342. for (let row = this.map.rows - 2; row >= 1; row -= 2) {
  343. this.getBlock(this.map.get_id(row, col))?.setState(BlockState.show);
  344. this.getBlock(this.map.get_id(row - 1, col))?.setState(BlockState.show);
  345. await this.delay.start(k);
  346. c += k;
  347. }
  348. }
  349. } else if (this.lv.dir == LvDir.down) {
  350. //向下,从左到右遍历------------------------------------------------------------
  351. for (let col = 1; col < this.map.cols - 1; col++) {
  352. for (let row = 1; row < this.map.rows - 1; row += 2) {
  353. this.getBlock(this.map.get_id(row, col))?.setState(BlockState.show);
  354. this.getBlock(this.map.get_id(row + 1, col))?.setState(BlockState.show);
  355. await this.delay.start(k);
  356. c += k;
  357. }
  358. }
  359. } else if (this.lv.dir == LvDir.right) {
  360. //向右
  361. for (let row = 1; row < this.map.rows - 1; row++) {
  362. for (let col = 1; col < this.map.cols - 1; col += 2) {
  363. this.getBlock(this.map.get_id(row, col))?.setState(BlockState.show);
  364. this.getBlock(this.map.get_id(row, col + 1))?.setState(BlockState.show);
  365. await this.delay.start(k);
  366. c += k;
  367. }
  368. }
  369. } else if (this.lv.dir == LvDir.left) {
  370. //向左
  371. for (let row = this.map.rows - 2; row >= 1; row--) {
  372. for (let col = 1; col < this.map.cols - 1; col += 2) {
  373. this.getBlock(this.map.get_id(row, col))?.setState(BlockState.show);
  374. this.getBlock(this.map.get_id(row, col + 1))?.setState(BlockState.show);
  375. await this.delay.start(k);
  376. c += k;
  377. }
  378. }
  379. }
  380. //------------------------------------------------
  381. let n = 1.5 - c;
  382. if (n <= 0) n = 0.2;
  383. await this.delay.start(n);
  384. for (let row = 1; row < this.map.rows - 1; row++) {
  385. for (let col = 1; col < this.map.cols - 1; col++) {
  386. this.getBlock(this.map.get_id(row, col))?.setState(BlockState.idle);
  387. }
  388. }
  389. this.state = GameState.wait;
  390. this.evt.emit(this.evt.key.game_wait);
  391. }
  392. //加载配置
  393. private loadTable(): void {
  394. ch.log.log_start("加载配置初始化");
  395. TableLoadUtil.preloadAll(ModuleDef.EXTRA, "table_json", async () => {
  396. }, TableUtil.set);
  397. }
  398. //
  399. public creatBlock(type: number): Block {
  400. const b = Block.Creat(type);
  401. this._bs.set(b.id, b);
  402. return b;
  403. }
  404. public getAllBlock(): Block[] {
  405. return Array.from(this._bs.values());
  406. }
  407. public getBlock(id: number): Block {
  408. if (!id) return null;
  409. return this._bs.get(id);
  410. }
  411. public removeBlock(id: number | Block): void {
  412. if (typeof id === 'number') {
  413. const t = this._bs.get(id);
  414. if (t) {
  415. this._bs.delete(id);
  416. t.dispose();
  417. }
  418. } else {
  419. this._bs.delete(id.id);
  420. id.dispose();
  421. }
  422. }
  423. public removeAllBlock(): void {
  424. this._bs.forEach((value, key) => {
  425. value.dispose();
  426. });
  427. this._bs.clear();
  428. }
  429. //
  430. public showBlockType(id: number | Block | null): void {
  431. if (!this.ver_b) return;
  432. if (this.state != GameState.wait) return;
  433. if (this._choose_id_a && this._choose_id_b) return;
  434. this._unchoose_a();
  435. if (id == null) {
  436. this.evt.emit(this.evt.key.show_block_type, 0, 0);
  437. return;
  438. }
  439. let b: Block;
  440. if (typeof id === 'number') {
  441. b = this._bs.get(id)
  442. } else {
  443. b = id;
  444. }
  445. this.evt.emit(this.evt.key.show_block_type, b.id, b.type);
  446. }
  447. //
  448. private _choose_id_a: number = null;
  449. private _choose_id_b: number = null;
  450. private _unchoose_a(): Block {
  451. if (!this._choose_id_a) return;
  452. const a = this.getBlock(this._choose_id_a);
  453. a.change_choose(0);
  454. this._choose_id_a = null;
  455. return a;
  456. }
  457. private _unchoose_b(): Block {
  458. if (!this._choose_id_b) return;
  459. const b = this.getBlock(this._choose_id_b);
  460. b.change_choose(0);
  461. this._choose_id_b = null;
  462. return b;
  463. }
  464. public async chooseBlock(id: number | Block) {
  465. if (this.state != GameState.wait) return;
  466. if (this._choose_id_a && this._choose_id_b) return;
  467. let b: Block;
  468. if (typeof id === 'number') {
  469. b = this._bs.get(id)
  470. } else {
  471. b = id;
  472. }
  473. if (b.state != BlockState.idle) return;
  474. b.change_choose(1);
  475. if (!this._choose_id_a) {
  476. this._choose_id_a = b.id;
  477. } else {
  478. const a = this.getBlock(this._choose_id_a);
  479. if (b.id === this._choose_id_a) {
  480. this._choose_id_a = null;
  481. a.change_choose(0);
  482. return;
  483. }
  484. this._choose_id_b = b.id;
  485. //
  486. const path = this.link.getMatch(a, b);
  487. if (path) {
  488. this.state = GameState.match;
  489. this.evt.emit(this.evt.key.show_path, path);
  490. } else {
  491. this._choose_id_a = null;
  492. this._choose_id_b = null;
  493. a.change_choose(0);
  494. b.change_choose(0);
  495. this.lv.change_life(-1);
  496. }
  497. }
  498. }
  499. public async eliminate() {
  500. const a = this._unchoose_a();
  501. const b = this._unchoose_b();
  502. const eliminate_point = [{ x: a.cx, y: a.cy }, { x: b.cx, y: b.cy }];
  503. this._choose_id_a = null;
  504. this._choose_id_b = null;
  505. this.removeBlock(a);
  506. this.removeBlock(b);
  507. this.un_tips();
  508. if (this._bs.size <= 0) {
  509. this.lv.win();
  510. } else {
  511. await this.move(eliminate_point);
  512. this.loop_ts();
  513. }
  514. }
  515. private loop_id: number;
  516. private async loop_ts() {
  517. if (!this.ver_b) return;
  518. if (this.loop_id) this.job.DeleteTimeTask(this.loop_id);
  519. this.loop_id = this.job.AddTimeTask(() => {
  520. if (this.state != GameState.wait) {
  521. this.job.DeleteTimeTask(this.loop_id);
  522. this.loop_id = null;
  523. return;
  524. }
  525. const bb = this.link.getLinkBlock();
  526. if (!bb) {
  527. UINotify.show('没有可消除的了,请洗牌');
  528. this.loop_ts();
  529. }
  530. }, 10);
  531. }
  532. private async move(list?: { x: number, y: number }[] | null): Promise<void> {
  533. this.state = GameState.move;
  534. switch (this.lv.dir) {
  535. case LvDir.left:
  536. if (list) {
  537. if (list[0].y == list[1].y) {
  538. const xx = Math.min(list[0].x, list[1].x);
  539. list = [{ x: xx, y: list[0].y }];
  540. }
  541. } else {
  542. list = [];
  543. for (let i = 1; i < this.map.cols - 1; i++) {
  544. list.push({ x: 1, y: i })
  545. }
  546. }
  547. for (let i = 0; i < list.length; i++) {
  548. const x = 1;
  549. const y = list[i].y;
  550. const move_list: Block[] = [];
  551. for (let n = x; n < this.map.rows - 1; n++) {
  552. const id = this.map.get_id(n, y);
  553. if (id) {
  554. const block = this.getBlock(id);
  555. move_list.push(block);
  556. }
  557. }
  558. for (let n = 0; n < move_list.length; n++) {
  559. if (move_list[n].SetCell(x + n, y)) move_list[n].setState(BlockState.move);
  560. }
  561. }
  562. break;
  563. case LvDir.right:
  564. if (list) {
  565. if (list[0].y == list[1].y) {
  566. const xx = Math.max(list[0].x, list[1].x);
  567. list = [{ x: xx, y: list[0].y }]
  568. }
  569. } else {
  570. list = [];
  571. for (let i = 1; i < this.map.cols - 1; i++) {
  572. list.push({ x: this.map.rows - 1, y: i })
  573. }
  574. }
  575. for (let i = 0; i < list.length; i++) {
  576. const x = this.map.rows - 1;
  577. const y = list[i].y;
  578. const move_list: Block[] = [];
  579. for (let n = x; n > 0; n--) {
  580. const id = this.map.get_id(n, y);
  581. if (id) {
  582. const block = this.getBlock(id);
  583. move_list.push(block);
  584. }
  585. }
  586. for (let n = 0; n < move_list.length; n++) {
  587. if (move_list[n].SetCell(x - n - 1, y)) move_list[n].setState(BlockState.move);
  588. }
  589. }
  590. break;
  591. case LvDir.up:
  592. if (list) {
  593. if (list[0].x === list[1].x) list = [{ x: list[0].x, y: 1 }];
  594. } else {
  595. list = [];
  596. for (let i = 1; i < this.map.rows - 1; i++) {
  597. list.push({ x: i, y: 1 })
  598. }
  599. }
  600. for (let i = 0; i < list.length; i++) {
  601. const y = 1;
  602. const x = list[i].x;
  603. const move_list: Block[] = [];
  604. for (let n = y; n < this.map.cols; n++) {
  605. const id = this.map.get_id(x, n);
  606. if (id) {
  607. const block = this.getBlock(id);
  608. move_list.push(block);
  609. }
  610. }
  611. for (let n = 0; n < move_list.length; n++) {
  612. if (move_list[n].SetCell(x, y + n)) move_list[n].setState(BlockState.move);
  613. }
  614. }
  615. break;
  616. case LvDir.down:
  617. if (list) {
  618. if (list[0].x === list[1].x) list = [{ x: list[0].x, y: this.map.cols - 1 }];
  619. } else {
  620. list = [];
  621. for (let i = 1; i < this.map.rows - 1; i++) {
  622. list.push({ x: i, y: this.map.cols - 1 })
  623. }
  624. }
  625. for (let i = 0; i < list.length; i++) {
  626. const y = this.map.cols - 1;
  627. const x = list[i].x;
  628. const move_list: Block[] = [];
  629. for (let n = y; n > 0; n--) {
  630. const id = this.map.get_id(x, n);
  631. if (id) {
  632. const block = this.getBlock(id);
  633. move_list.push(block);
  634. }
  635. }
  636. for (let n = 0; n < move_list.length; n++) {
  637. if (move_list[n].SetCell(x, y - 1 - n)) move_list[n].setState(BlockState.move);
  638. }
  639. }
  640. break;
  641. case LvDir.xCenter:
  642. if (list) {
  643. if (list[0].y == list[1].y) list = [list[0]];
  644. } else {
  645. list = [];
  646. for (let i = 1; i < this.map.cols - 1; i++) list.push({ x: this.map.rows - 1, y: i });
  647. }
  648. for (let i = 0; i < list.length; i++) {
  649. const k = this.map.rows * 0.5;
  650. const y = list[i].y;
  651. const move_list: Block[] = [];
  652. for (let n = k; n < this.map.rows - 1; n++) {
  653. const id = this.map.get_id(n, y);
  654. if (id) {
  655. const block = this.getBlock(id);
  656. move_list.push(block);
  657. }
  658. }
  659. for (let n = 0; n < move_list.length; n++) {
  660. if (move_list[n].SetCell(k + n, y)) move_list[n].setState(BlockState.move);
  661. }
  662. move_list.length = 0;
  663. for (let n = k - 1; n > 0; n--) {
  664. const id = this.map.get_id(n, y);
  665. if (id) {
  666. const block = this.getBlock(id);
  667. move_list.push(block);
  668. }
  669. }
  670. for (let n = 0; n < move_list.length; n++) {
  671. if (move_list[n].SetCell(k - 1 - n, y)) move_list[n].setState(BlockState.move);
  672. }
  673. }
  674. break;
  675. case LvDir.xOut:
  676. if (list) {
  677. if (list[0].y == list[1].y) list = [list[0]];
  678. } else {
  679. list = [];
  680. for (let i = 1; i < this.map.cols - 1; i++) list.push({ x: this.map.rows - 1, y: i });
  681. }
  682. for (let i = 0; i < list.length; i++) {
  683. const k = this.map.rows * 0.5;
  684. const y = list[i].y;
  685. const move_list: Block[] = [];
  686. for (let n = this.map.rows - 1; n >= k; n--) {
  687. const id = this.map.get_id(n, y);
  688. if (id) {
  689. const block = this.getBlock(id);
  690. move_list.push(block);
  691. }
  692. }
  693. for (let n = 0; n < move_list.length; n++) {
  694. if (move_list[n].SetCell(this.map.rows - 2 - n, y)) move_list[n].setState(BlockState.move);
  695. }
  696. move_list.length = 0;
  697. for (let n = 1; n < k; n++) {
  698. const id = this.map.get_id(n, y);
  699. if (id) {
  700. const block = this.getBlock(id);
  701. move_list.push(block);
  702. }
  703. }
  704. for (let n = 0; n < move_list.length; n++) {
  705. if (move_list[n].SetCell(n + 1, y)) move_list[n].setState(BlockState.move);
  706. }
  707. }
  708. break;
  709. case LvDir.yCenter:
  710. if (list) {
  711. if (list[0].x == list[1].x) list = [list[0]];
  712. } else {
  713. list = [];
  714. for (let i = 1; i < this.map.rows - 1; i++) list.push({ x: i, y: this.map.cols - 1 });
  715. }
  716. for (let i = 0; i < list.length; i++) {
  717. const k = this.map.cols * 0.5;
  718. const x = list[i].x;
  719. const move_list: Block[] = [];
  720. for (let n = k; n < this.map.cols - 1; n++) {
  721. const id = this.map.get_id(x, n);
  722. if (id) {
  723. const block = this.getBlock(id);
  724. move_list.push(block);
  725. }
  726. }
  727. for (let n = 0; n < move_list.length; n++) {
  728. if (move_list[n].SetCell(x, k + n)) move_list[n].setState(BlockState.move);
  729. }
  730. move_list.length = 0;
  731. for (let n = k - 1; n > 0; n--) {
  732. const id = this.map.get_id(x, n);
  733. if (id) {
  734. const block = this.getBlock(id);
  735. move_list.push(block);
  736. }
  737. }
  738. for (let n = 0; n < move_list.length; n++) {
  739. if (move_list[n].SetCell(x, k - 1 - n)) move_list[n].setState(BlockState.move);
  740. }
  741. }
  742. break;
  743. case LvDir.yOut:
  744. if (list) {
  745. if (list[0].x == list[1].x) list = [list[0]];
  746. } else {
  747. list = [];
  748. for (let i = 1; i < this.map.rows - 1; i++) list.push({ x: i, y: this.map.cols - 1 });
  749. }
  750. for (let i = 0; i < list.length; i++) {
  751. const k = this.map.cols * 0.5; // 中心行
  752. const x = list[i].x;
  753. const move_list: Block[] = [];
  754. // 检查当前块下方的所有格子
  755. for (let n = this.map.cols - 1; n >= k; n--) {
  756. const id = this.map.get_id(x, n);
  757. if (id) {
  758. const block = this.getBlock(id);
  759. move_list.push(block);
  760. }
  761. }
  762. // 移动下方块
  763. for (let n = 0; n < move_list.length; n++) {
  764. if (move_list[n].SetCell(x, this.map.cols - 2 - n)) move_list[n].setState(BlockState.move);
  765. }
  766. //清空移动列表
  767. move_list.length = 0;
  768. //检查当前块上方的所有格子
  769. for (let n = 1; n < k; n++) {
  770. const id = this.map.get_id(x, n);
  771. if (id) {
  772. const block = this.getBlock(id);
  773. move_list.push(block);
  774. }
  775. }
  776. // 移动上方块
  777. for (let n = 0; n < move_list.length; n++) {
  778. if (move_list[n].SetCell(x, n + 1)) move_list[n].setState(BlockState.move);
  779. }
  780. }
  781. break;
  782. }
  783. if (this.lv.dir != LvDir.none) {
  784. await this.delay.start(0.3);
  785. }
  786. this.state = GameState.wait;
  787. }
  788. private _tipsa: number;
  789. private _tipsb: number;
  790. private un_tips(): void {
  791. if (this._tipsa) {
  792. this.getBlock(this._tipsa)?.change_choose(0);
  793. this._tipsa = null;
  794. }
  795. if (this._tipsb) {
  796. this.getBlock(this._tipsb)?.change_choose(0);
  797. this._tipsb = null;
  798. }
  799. }
  800. /**提示*/
  801. public tips(): boolean {
  802. if (this.state != GameState.wait) return false;
  803. if (this._choose_id_a && this._choose_id_b) return false;
  804. this._unchoose_a();
  805. const bb = this.link.getLinkBlock();
  806. if (bb) {
  807. bb.a.change_choose(2);
  808. bb.b.change_choose(2);
  809. this._tipsa = bb.a.id;
  810. this._tipsb = bb.b.id;
  811. this.lv.record.item1++;
  812. return true;
  813. } else {
  814. notify('没有可消除的了,请洗牌');
  815. return false;
  816. }
  817. }
  818. /**刷新*/
  819. public sx(): boolean {
  820. if (this.state != GameState.wait) return false;
  821. if (this._choose_id_a && this._choose_id_b) return false;
  822. this.un_tips();
  823. this._unchoose_a();
  824. const bs = this.getAllBlock();
  825. let ts: number[] = []
  826. for (let i = 0; i < bs.length; i++) {
  827. ts.push(bs[i].type);
  828. }
  829. for (let i = ts.length - 1; i > 0; i--) {
  830. const j = Math.floor(Math.random() * (i + 1));
  831. [ts[i], ts[j]] = [ts[j], ts[i]];
  832. }
  833. for (let i = 0; i < bs.length; i++) {
  834. bs[i].change_type(ts[i]);
  835. }
  836. this.lv.record.item2++;
  837. return true;
  838. }
  839. //
  840. public add_hp(): boolean {
  841. if (this.lv.life >= 6) {
  842. notify('生命值已达到上限');
  843. return false;
  844. }
  845. this.lv.change_life(3);
  846. this.lv.record.item3++;
  847. return true;
  848. }
  849. //
  850. public change_dir(): boolean {
  851. if (this.state != GameState.wait) return false;
  852. if (this._choose_id_a && this._choose_id_b) return false;
  853. this.un_tips();
  854. this.lv.change_dir();
  855. if (this.lv.dir == LvDir.none) return false;
  856. this.move();
  857. return true;
  858. }
  859. }
  860. export function notify(msg: string): void {
  861. UINotify.show(msg);
  862. }
  863. export function button_sound(): void {
  864. ch.audio.playOneShot('sounds/sfx_button');
  865. }
  866. export function ani_ui(node: Node, end: number = 1.0): void {
  867. gui.scale_elasticOut_anim(node, 1.2, 0.5, end);
  868. }
  869. export function repair_ani_ui(node: Node, end: number = 1.15): void {
  870. gui.scale_elasticOut_anim(node, 1.2, 0.5, end);
  871. }