GameNode.ts 28 KB

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