GameNode.ts 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. import { _decorator, geometry, Node, Camera, screen, EventTouch, Prefab, instantiate, v3, tween, RigidBody, MeshRenderer, Vec3, find, input, Input, Tween, PhysicsSystem, view } from 'cc';
  2. import { TileItem } from './TileItem';
  3. import { Main } from './Main';
  4. import { ResUtil } from '../core/utils/ResUtil';
  5. import { ComponentEx } from '../core/component/ComponentEx';
  6. import { audioMgr } from '../core/manager/AudioManager';
  7. import BusyLoadingManager, { BUSY_TYPE } from '../core/manager/BusyLoadingManager';
  8. import Data from '../core/manager/Data';
  9. import WindowManager from '../core/manager/WindowManager';
  10. import MsgHints from '../core/utils/MsgHints';
  11. import Utils from '../core/utils/Utils';
  12. import { DrawStarLayer } from '../gameui/DrawStarLayer';
  13. import { eventEmitter } from '../core/event/EventEmitter';
  14. import platformSystem from '../platform/platformSystem';
  15. import { GameConst, ITEM_TYPE } from '../core/common/GameConst';
  16. import { levelsData } from '../user/LevelsData';
  17. const { Ray } = geometry;
  18. const { ccclass, property, executeInEditMode } = _decorator;
  19. @ccclass('GameNode')
  20. export class GameNode extends ComponentEx {
  21. @property({type: Node,tooltip:"底部的盘子"})
  22. public plate: Node = null;
  23. public collectpos: Vec3[] = [];
  24. public collectTiles: Node[] = [];
  25. public allTiles: Node[] = [];
  26. public optionTiles: Node[] = [];
  27. public start() {
  28. setTimeout(() => {
  29. this.initWall();
  30. this.collectpos = [];
  31. this.GetNode("collectbox").children.map(a => {
  32. this.collectpos.push(a.worldPosition);
  33. a.active = false;
  34. })
  35. }, 100);
  36. eventEmitter.register(this, GameConst.CLEAR_ALL_BOX, () => {
  37. console.log("清空盒子")
  38. this.lock=false
  39. setTimeout(() => {
  40. for (let i = 0; i < this.collectTiles.length; ++i) {
  41. this.pushBask(this.collectTiles[i].name);
  42. }
  43. this.collectTiles.map(a => {
  44. a.destroy();
  45. })
  46. this.collectTiles = [];
  47. }, 500);
  48. })
  49. //提示
  50. eventEmitter.register(this, GameConst.USE_ITEM_HINT,this.prompt.bind(this))
  51. }
  52. onEnable() {
  53. input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
  54. input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
  55. input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
  56. }
  57. onDisable() {
  58. input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
  59. input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this);
  60. input.off(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
  61. }
  62. moveToRightPos() {
  63. return;
  64. //移动到正确位置
  65. this.collectTiles.map((a, i) => {
  66. let tileItem = a.getComponent(TileItem)
  67. Tween.stopAllByTarget(a);
  68. //抛物移动
  69. /*this.parabolicMovementWithScale(
  70. a,
  71. a.position.clone(),
  72. this.collectpos[i].clone(),
  73. 4, //高度
  74. 0.4, //时长
  75. a.scale.clone(),
  76. new Vec3(1, 1, 1),
  77. ()=>{
  78. tileItem.auto_rotation = true;
  79. if (tileItem.removed) {
  80. Utils.remove(this.optionTiles,a);
  81. tween(a).to(0.25, { worldPosition: tileItem.removedPos }, { easing: 'backIn' }).call(async () => {
  82. //最中央的播放移除特效
  83. if (tileItem.playRmovedEff) {
  84. //增加星星
  85. let pos = this.GetNode("Main Camera").getComponent(Camera).convertToUINode(a.worldPosition, find("Canvas"));
  86. let node_ani = await ResUtil.playSkAni("spine/effect_hecheng", "effect", find("Canvas"), pos);
  87. audioMgr.playOneShot(GameConst.audios.starCollect);
  88. platformSystem.platform.vibrateShort();
  89. Utils.flyAnim(ITEM_TYPE.Star, node_ani, Main.Instance()._GameUI.starNode, 1, 0, (b) => {
  90. if (b) {
  91. node_ani.destroy();
  92. Main.Instance()._GameUI.star++;
  93. }
  94. });
  95. }
  96. a.destroy()
  97. this.moveToRightPos()
  98. this.checkResult()
  99. }).start()
  100. }
  101. }
  102. );*/
  103. tween(a).to(0.3, { worldPosition: this.collectpos[i].clone(), worldScale: v3(1, 1, 1) }).call(() => {
  104. tileItem.auto_rotation = true;
  105. if (tileItem.removed) {
  106. Utils.remove(this.optionTiles,a);
  107. tween(a).to(0.25, { worldPosition: tileItem.removedPos }, { easing: 'backIn' }).call(async () => {
  108. //最中央的播放移除特效
  109. if (tileItem.playRmovedEff) {
  110. //增加星星
  111. let pos = this.GetNode("Main Camera").getComponent(Camera).convertToUINode(a.worldPosition, find("Canvas"));
  112. let node_ani = await ResUtil.playSkAni("spine/effect_hecheng", "effect", find("Canvas"), pos);
  113. audioMgr.playOneShot(GameConst.audios.starCollect);
  114. platformSystem.platform.vibrateShort();
  115. Utils.flyAnim(ITEM_TYPE.Star, node_ani, Main.Instance()._GameUI.starNode, 1, 0, (b) => {
  116. if (b) {
  117. node_ani.destroy();
  118. Main.Instance()._GameUI.star++;
  119. }
  120. });
  121. }
  122. a.destroy()
  123. this.moveToRightPos()
  124. this.checkResult()
  125. }).start()
  126. }
  127. }).start();
  128. })
  129. }
  130. chooseTile(tile: Node) {
  131. let chooseName = tile.name;
  132. this.optionTiles.push(tile);
  133. //删除点击对象从列表
  134. tile.getComponent(TileItem).destoryCollider()
  135. for (var i = 0; i < this.allTiles.length; ++i) {
  136. if (this.allTiles[i] == tile) {
  137. this.allTiles.splice(i, 1);
  138. break;
  139. }
  140. }
  141. //插入
  142. let bInsert = false;
  143. for (var i = this.collectTiles.length - 1; i >= 0; --i) {
  144. if (this.collectTiles[i].name == chooseName) {
  145. this.collectTiles.splice(i + 1, 0, tile);
  146. bInsert = true;
  147. break;
  148. }
  149. }
  150. if (!bInsert) {
  151. this.collectTiles.push(tile);
  152. }
  153. this.moveToRightPos()
  154. //检测要删除的
  155. let tmp = this.collectTiles.filter(a => {
  156. return a.name == chooseName;
  157. })
  158. if (tmp.length == 3) {
  159. for (var i = this.collectTiles.length - 1; i >= 0; --i) {
  160. if (this.collectTiles[i].name == chooseName) {
  161. let delNode = this.collectTiles[i];
  162. delNode.getComponent(TileItem).removed = true
  163. this.collectTiles.splice(i, 1);
  164. delNode.getComponent(TileItem).removedPos = tmp[1].worldPosition
  165. if (delNode == tmp[1])
  166. delNode.getComponent(TileItem).playRmovedEff = true
  167. }
  168. }
  169. }
  170. this.checkResult()
  171. }
  172. lock=false
  173. checkResult() {
  174. if(this.lock)return
  175. //检测胜利和失败
  176. if (this.collectTiles.length >= 7) {
  177. this.lock=true
  178. if (!WindowManager.ins.isShow("OutOfBoxLayer"))
  179. WindowManager.ins.open("OutOfBoxLayer");
  180. } else if (this.collectTiles.length == 0 && this.allTiles.length == 0) {
  181. this.lock=true
  182. WindowManager.ins.open("DrawStarLayer").then((com: DrawStarLayer) => {
  183. com.setStar(Main.Instance()._GameUI.star);
  184. })
  185. }
  186. }
  187. private touchTileItem: TileItem = null;
  188. onTouchStart(event: EventTouch) {
  189. if (Main.Instance()._GameUI.pasue) return;
  190. if (Data.user.useMagnet) return;
  191. if (this.allTiles.length == 0) return;
  192. if (this.collectTiles.length >= 7) {
  193. return;
  194. }
  195. const p = event.getLocation();
  196. let camera = this.GetNode("Main Camera").getComponent(Camera);
  197. const r = new Ray();
  198. camera?.screenPointToRay(p.x, p.y, r);
  199. let b = PhysicsSystem.instance.raycastClosest(r, 1)
  200. if (b) {
  201. let collider = PhysicsSystem.instance.raycastClosestResult.collider;
  202. if(!collider.getComponent(RigidBody))return;
  203. console.log(collider.node.name, collider.getComponent(RigidBody).group);
  204. let item = collider.node.parent.getComponent(TileItem);
  205. if (item) {
  206. item.enableCollider = false;
  207. let pos = item.node.getWorldPosition();
  208. pos.y += 0.3;
  209. item.node.setWorldPosition(pos);
  210. this.touchTileItem = item;
  211. }
  212. }
  213. }
  214. onTouchEnd(event: EventTouch) {
  215. if (Main.Instance()._GameUI.pasue) return;
  216. if (Data.user.useMagnet) return;
  217. if (!this.touchTileItem) return;
  218. if (this.allTiles.length == 0) return;
  219. if (this.collectTiles.length >= 7) {
  220. return;
  221. }
  222. const p = event.getLocation();
  223. let camera = this.GetNode("Main Camera").getComponent(Camera);
  224. const r = new Ray();
  225. camera?.screenPointToRay(p.x, p.y, r);
  226. let b = PhysicsSystem.instance.raycastClosest(r, 1);
  227. if (b) {
  228. let collider = PhysicsSystem.instance.raycastClosestResult.collider;
  229. if(!collider.getComponent(RigidBody))return;
  230. let item = collider.node.parent.getComponent(TileItem);
  231. if (item && item == this.touchTileItem) {
  232. platformSystem.platform.vibrateShort();
  233. this.chooseTile(item.node);
  234. this.touchTileItem = null;
  235. audioMgr.playOneShot(GameConst.audios.tap);
  236. }else {
  237. this.touchTileItem.enableCollider = true;
  238. }
  239. }
  240. }
  241. onTouchMove(event: EventTouch) {
  242. if (Main.Instance()._GameUI.pasue) return;
  243. if (Data.user.useMagnet) return;
  244. if (this.allTiles.length == 0) return;
  245. if (this.collectTiles.length >= 7) {
  246. return;
  247. }
  248. const p = event.getLocation();
  249. let camera = this.GetNode("Main Camera").getComponent(Camera);
  250. const r = new Ray();
  251. camera?.screenPointToRay(p.x, p.y, r);
  252. let b = PhysicsSystem.instance.raycastClosest(r, 1)
  253. if (b) {
  254. let collider = PhysicsSystem.instance.raycastClosestResult.collider
  255. if(!collider.getComponent(RigidBody))return;
  256. let item = collider.node.parent.getComponent(TileItem);
  257. if (item) {
  258. if (this.touchTileItem && item == this.touchTileItem) {
  259. }else {
  260. if (this.touchTileItem) this.touchTileItem.enableCollider = true;
  261. item.enableCollider = false;
  262. let pos = item.node.getWorldPosition();
  263. pos.y += 0.3;
  264. // console.log("切换")
  265. item.node.setWorldPosition(pos);
  266. this.touchTileItem = item;
  267. }
  268. }
  269. else {
  270. if (this.touchTileItem) {
  271. // console.log("无目标")
  272. this.touchTileItem.enableCollider = true;
  273. this.touchTileItem = null;
  274. }
  275. }
  276. }
  277. }
  278. initWall() {
  279. if (!PhysicsSystem.instance) return;
  280. const OFFSET = 25;
  281. let camera = this.GetNode("Main Camera").getComponent(Camera);
  282. const r = new Ray();
  283. let size = screen.windowSize;
  284. //左边墙
  285. camera?.screenPointToRay(OFFSET, size.height / 2, r);
  286. if (PhysicsSystem.instance.raycastClosest(r)) {
  287. const result = PhysicsSystem.instance.raycastClosestResult;
  288. this.GetNode("PlaneLeft").setWorldPosition(result.hitPoint);
  289. }
  290. //右边墙
  291. camera?.screenPointToRay(size.width - OFFSET, size.height / 2, r);
  292. if (PhysicsSystem.instance.raycastClosest(r)) {
  293. const result = PhysicsSystem.instance.raycastClosestResult;
  294. this.GetNode("PlaneRight").setWorldPosition(result.hitPoint);
  295. }
  296. //上边墙
  297. camera?.screenPointToRay(size.width / 2, size.height - OFFSET * 4, r);
  298. if (PhysicsSystem.instance.raycastClosest(r)) {
  299. const result = PhysicsSystem.instance.raycastClosestResult;
  300. this.GetNode("PlaneTop").setWorldPosition(result.hitPoint);
  301. }
  302. let minx = this.GetNode("PlaneLeft").worldPosition.x;
  303. let maxx = this.GetNode("PlaneRight").worldPosition.x;
  304. let scale = (maxx - minx) / 8.461091041564941;
  305. this.GetNode("bottom").scale = v3(scale, scale, scale);
  306. //格子位置
  307. camera?.screenPointToRay(size.width / 2, 10, r);
  308. if (PhysicsSystem.instance.raycastClosest(r)) {
  309. const result = PhysicsSystem.instance.raycastClosestResult;
  310. //result.hitPoint
  311. let p: Vec3 = new Vec3(result.hitPoint.x,4,result.hitPoint.z);
  312. this.GetNode("bottom").setWorldPosition(p);
  313. }
  314. //下边墙
  315. this.GetNode("PlaneDown").setWorldPosition(this.GetNode("bottom").worldPosition.add3f(0, 0, -2.5 * scale));
  316. }
  317. async createTiles() {
  318. let Margin = 0
  319. let minx = this.GetNode("PlaneLeft").worldPosition.x + Margin;
  320. let maxx = this.GetNode("PlaneRight").worldPosition.x - Margin;
  321. let maxz = this.GetNode("PlaneDown").worldPosition.z + Margin;
  322. let minz = this.GetNode("PlaneTop").worldPosition.z - Margin;
  323. let obj = levelsData.getCurLevelInfo();
  324. console.log("FFFFFFFFF" + JSON.stringify(obj));
  325. //数量
  326. let tileCount = Math.floor(obj.count / 3);
  327. // if (Data.user.lv == 1) tileCount = 2;
  328. // tiles = Utils.shuffle(tiles);
  329. let tilepools = [];// 30 /2 = 15
  330. let count1 = Math.floor(tileCount / 2);
  331. let count2 = tileCount - count1;
  332. //1从解锁池选一半
  333. let OpenItems:Array<string> = levelsData.getModesNames();
  334. for (let i = Data.user.openIndex - 1; i >= 0; --i) {
  335. tilepools.push(OpenItems[i]);
  336. count1--;
  337. if (count1 == 0) {
  338. break;
  339. }
  340. }
  341. console.log("解锁取", tileCount - (count2 + count1), "标准取", tileCount - (tileCount - (count2 + count1)))
  342. //2从标准池选一半
  343. let ItemNames:Array<string> = levelsData.getModesNames();
  344. for(let k = count2 + count1 - 1; k >= 0; --k) {
  345. tilepools.push(ItemNames[k]);
  346. }
  347. tilepools = Utils.shuffle(tilepools);
  348. Main.Instance()._GameUI.pasue = true;
  349. BusyLoadingManager.ins.addBusy(BUSY_TYPE.RES);
  350. for (let i = 0; i < tileCount; i++) {
  351. let ret = await ResUtil.loadModelPrefabName(tilepools[i]) as Prefab;
  352. if (!ret) continue;
  353. //获取节点下的 MeshRenderer 组件 设置阴影投射模式
  354. (ret.data.getComponentInChildren(MeshRenderer) as MeshRenderer).shadowCastingMode = MeshRenderer.ShadowCastingMode.ON;
  355. for (let j = 0; j < 3; j++) {
  356. const globalIndex = (i * 3 + j) % 9;
  357. let lnode = this.GetNode(`l${globalIndex}`);
  358. tween(this.node).delay(j * 0.03).call(() => {
  359. let nomal_node: Node = instantiate(ret);
  360. nomal_node.name = ret.name;
  361. let tile = nomal_node.addComponent(TileItem);
  362. let rigid = tile.addCollider();
  363. nomal_node.scale = v3(1.25, 1.25, 1.25)
  364. if (Data.user.lv == 1) {
  365. nomal_node.setWorldPosition(lnode.getWorldPosition());
  366. nomal_node.parent = this.node;
  367. this.allTiles.push(nomal_node);
  368. }else{
  369. let p = v3(Utils.getRandomInt(minx / 2, maxx / 2), Utils.getRandom(12, 15), Utils.getRandomInt(minz / 2, maxz / 2));
  370. nomal_node.setWorldRotationFromEuler(Utils.getRandom(0, 300), Utils.getRandom(0, 300), Utils.getRandom(0, 300))
  371. nomal_node.setWorldPosition(p);
  372. nomal_node.parent = this.node;
  373. rigid.applyImpulse(v3(0, 3, 0))
  374. this.allTiles.push(nomal_node);
  375. }
  376. }).start()
  377. }
  378. if (i == tileCount - 1) {
  379. BusyLoadingManager.ins.removeBusy(BUSY_TYPE.RES);
  380. Main.Instance()._GameUI.pasue = false;
  381. }
  382. }
  383. setTimeout(() => {
  384. if (Data.user.useMagnet) {
  385. Main.Instance()._GameUI.pasue = true;
  386. Data.user.magnet--;
  387. let p = this.GetNode("magnet").worldPosition;
  388. this.GetNode("magnet").worldPosition = v3(-10, p.y, p.z);
  389. tween(this.GetNode("magnet")).to(0.5, { worldPosition: v3(0, p.y, p.z) }).call(async () => {
  390. let arr = [];
  391. for (var i = this.allTiles.length - 1; i >= 0; --i) {
  392. let pick = false;
  393. let item = this.allTiles[i];
  394. let tmp: Node = arr[0];
  395. if(tmp){
  396. if (tmp.name == item.name && arr.length < 3) {
  397. arr.push(item);
  398. pick = true;
  399. }
  400. }else{
  401. arr.push(item);
  402. pick = true;
  403. }
  404. if(pick) {
  405. let tile: TileItem = this.allTiles[i].getComponent(TileItem);
  406. tile.destoryCollider();
  407. this.GetNode("magnet_content").addChild(tile.node);
  408. tween(tile.node).to(0.5, { worldPosition: this.GetNode(arr.length % 2 ? "m_left" : "r_left").worldPosition }).start();
  409. this.allTiles.splice(i, 1);
  410. console.log("删除", tile.name, this.allTiles.length)
  411. }
  412. }
  413. Data.user.useMagnet = false;
  414. }).delay(1.5).to(0.5, { worldPosition: v3(10, p.y, p.z) }).call(() => {
  415. this.GetNode("magnet_content").removeAllChildren();
  416. Main.Instance()._GameUI.pasue = false;
  417. if (Data.user.useTime && Data.user.time > 0)
  418. eventEmitter.dispatch(GameConst.USE_ITEM_TIME)
  419. }).start();
  420. }else {
  421. if (Data.user.useTime && Data.user.time > 0){
  422. eventEmitter.dispatch(GameConst.USE_ITEM_TIME)}
  423. }
  424. }, 2000);
  425. }
  426. /**
  427. * 提示
  428. */
  429. restart() {
  430. this.allTiles.map(a => a.destroy());
  431. this.allTiles = [];
  432. Main.Instance()._GameUI.star = 0;
  433. this.collectTiles.map(a => a.destroy());
  434. this.collectTiles = [];
  435. this.createTiles();
  436. this.lock=false
  437. }
  438. /**移除*/
  439. public remove(){
  440. if (this.optionTiles.length === 0 || this.lock) return;
  441. // 获取最后一个收集的物品
  442. const lastItem = this.optionTiles.pop();
  443. if (!lastItem) return;
  444. Utils.remove(this.collectTiles,lastItem);
  445. const tile = lastItem.getComponent(TileItem);
  446. tile.removed = false;
  447. tile.auto_rotation = false;
  448. //播放撤销动画
  449. Tween.stopAllByTarget(lastItem);
  450. //const globalIndex = Math.floor(Math.random() * 9);
  451. let lnode = this.GetNode(`l${4}`);
  452. let p:Vec3 = lnode.position.clone();
  453. tween(tile.node)
  454. .to(0.35, {
  455. worldPosition: new Vec3(p.x,p.y + 1,p.z),
  456. worldScale: v3(1.25, 1.25, 1.25)
  457. })
  458. .call(() => {
  459. tile.addCollider();
  460. tile.enableCollider = true;
  461. this.allTiles.push(lastItem);
  462. //向上施加力 然后在向下重力效果
  463. tile.rigid.applyImpulse(v3(0, 3, 0))
  464. this.moveToRightPos(); // 重新排列收集框中的物品
  465. })
  466. .start();
  467. }
  468. /**乱序*/
  469. public mess(){
  470. if(this.allTiles.length === 0 || this.lock) return;
  471. this.allTiles.forEach((item, index) => {
  472. const tileItem = item.getComponent(TileItem);
  473. tileItem.auto_rotation = false;
  474. tileItem.enableCollider = true;
  475. Tween.stopAllByTarget(item);
  476. tween(item)
  477. .to(0.3, {
  478. worldPosition: this.GetNode("l4").worldPosition.clone().add(v3(0, 1, 0)),
  479. worldScale: v3(1.25, 1.25, 1.25)
  480. })
  481. .call(() => {
  482. const rigid = tileItem.addCollider();
  483. rigid.applyImpulse(v3(
  484. Utils.getRandom(-3, 3),
  485. Utils.getRandom(5, 8),
  486. Utils.getRandom(-3, 3)
  487. ));
  488. item.setWorldRotationFromEuler(Utils.getRandom(0, 300), Utils.getRandom(0, 300), Utils.getRandom(0, 300))
  489. })
  490. .start();
  491. });
  492. //audioManager.playOneShot(GameConst.audios.shuffle);
  493. platformSystem.platform.vibrateShort();
  494. }
  495. /**凑齐*/
  496. public prompt(){
  497. if(this.collectTiles.length <= 0)return;
  498. let obj = {}
  499. for (var i = 0; i < this.collectTiles.length; ++i) {
  500. let name = this.collectTiles[i].name;
  501. if (!obj[name]) obj[name] = 0;
  502. obj[name]++;
  503. }
  504. let hint_succ = false;
  505. let bFind = false;
  506. let hint_name = ""
  507. for (const key in obj) {
  508. if (obj[key] == 2) {
  509. hint_name = key;
  510. bFind = true;
  511. break;
  512. }
  513. }
  514. //找到两个一样
  515. if (bFind) {
  516. console.log("找到两个一样")
  517. for (let i = 0; i < this.allTiles.length; ++i) {
  518. if (this.allTiles[i].name == hint_name) {
  519. this.chooseTile(this.allTiles[i]);
  520. break;
  521. }
  522. }
  523. hint_succ = true;
  524. }else {
  525. if (this.collectTiles.length >= 5) {
  526. MsgHints.show("未找到合适物品");
  527. return
  528. }else {
  529. hint_name = this.collectTiles[0] ? this.collectTiles[0].name : this.allTiles[0].name;
  530. let lsit = this.allTiles.filter(a => {
  531. return a.name == hint_name;
  532. })
  533. lsit.map((a, i) => {
  534. setTimeout(() => {
  535. this.chooseTile(a);
  536. }, 350 * i);
  537. })
  538. hint_succ = true;
  539. }
  540. }
  541. if (hint_succ) {
  542. Data.user.hint--;
  543. }
  544. }
  545. //放回场景中
  546. async pushBask(name: string) {
  547. let Margin = 0;
  548. let maxz = this.GetNode("PlaneDown").worldPosition.z + Margin;
  549. let minz = this.GetNode("PlaneTop").worldPosition.z - Margin;
  550. let minx = this.GetNode("PlaneLeft").worldPosition.x + Margin;
  551. let maxx = this.GetNode("PlaneRight").worldPosition.x - Margin;
  552. let ret = await ResUtil.loadModelPrefabName(name) as Prefab;
  553. let nomal_node: Node = instantiate(ret);
  554. nomal_node.name = name;
  555. let tile = nomal_node.addComponent(TileItem);
  556. let rigid = tile.addCollider();
  557. nomal_node.scale = v3(1.25,1.25, 1.25)
  558. nomal_node.parent = this.node;
  559. rigid.applyImpulse(v3(0, 3, 0))
  560. let p = v3(minx + (maxx - minx) / 2, Utils.getRandom(12, 15), minz + (maxz - minz) / 2);
  561. nomal_node.setWorldRotationFromEuler(Utils.getRandom(0, 300), Utils.getRandom(0, 300), Utils.getRandom(0, 300))
  562. nomal_node.setWorldPosition(p);
  563. this.allTiles.push(nomal_node);
  564. }
  565. /**
  566. * 抛物线运动工具(带缩放动画)
  567. * @param node 要移动的节点
  568. * @param startPos 起始坐标(世界坐标)
  569. * @param endPos 目标坐标(世界坐标)
  570. * @param height 抛物线最高点高度(相对于起点)
  571. * @param duration 动画时长(秒)
  572. * @param startScale 起始缩放(默认原始大小)
  573. * @param endScale 目标缩放(默认原始大小)
  574. * @param onComplete 完成回调
  575. */
  576. public parabolicMovementWithScale(
  577. node: Node,
  578. startPos: Vec3,
  579. endPos: Vec3,
  580. height: number = 2,
  581. duration: number = 1.5,
  582. startScale: Vec3 = Vec3.ONE,
  583. endScale: Vec3 = Vec3.ONE,
  584. onComplete?: () => void
  585. ): Tween<Node> {
  586. if(Vec3.equals(startPos, endPos)) {
  587. onComplete?.();
  588. return;
  589. }
  590. //初始化节点状态
  591. node.setWorldPosition(startPos.clone());
  592. node.setScale(startScale);
  593. //计算抛物线顶点
  594. const midPoint = new Vec3(
  595. (startPos.x + endPos.x) / 2,
  596. Math.max(startPos.y, endPos.y) + height,
  597. (startPos.z + endPos.z) / 2
  598. );
  599. //创建组合动画
  600. return tween(node)
  601. .to(duration,
  602. {
  603. worldPosition: endPos,
  604. worldScale: endScale
  605. },
  606. {
  607. onUpdate: (target: Node, ratio: number) => {
  608. //1. 计算抛物线位置
  609. const t = ratio;
  610. const invT = 1 - t;
  611. const tempPos = new Vec3();
  612. // XZ轴线性插值
  613. Vec3.lerp(tempPos, startPos, endPos, t);
  614. //Y轴抛物线计算
  615. const y = invT * invT * startPos.y
  616. + 2 * invT * t * midPoint.y
  617. + t * t * endPos.y;
  618. //2. 计算当前缩放比例
  619. const currentScale = new Vec3();
  620. Vec3.lerp(currentScale, startScale, endScale, t);
  621. //更新节点状态
  622. target.worldPosition = new Vec3(tempPos.x, y, tempPos.z);
  623. target.setScale(currentScale);
  624. }
  625. }
  626. )
  627. .call(() => {
  628. // 最终确保缩放精确
  629. node.setScale(endScale);
  630. onComplete?.();
  631. })
  632. .start();
  633. }
  634. }