index.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. Component({
  2. behaviors: [require('../common/share-behavior').default],
  3. properties: {
  4. markerImg: {
  5. type: String
  6. },
  7. },
  8. data: {
  9. loaded: false,
  10. arReady: false,
  11. isStartPlay1: false,
  12. adlScale: '0 0 0',
  13. adlPos: '-0.1 -0.5 -0.05',
  14. sunReady: false,
  15. tigerReady: false
  16. },
  17. lifetimes: {
  18. attached() {
  19. },
  20. detached() {
  21. this.stopSunRotation();
  22. this.stopTiger();
  23. }
  24. },
  25. methods: {
  26. handleReady({
  27. detail
  28. }) {
  29. const xrScene = this.scene = detail.value;
  30. // console.log('xr-scene', xrScene);
  31. },
  32. handleAssetsProgress: function ({
  33. detail
  34. }) {
  35. // console.log('assets progress', detail.value);
  36. },
  37. handleAssetsLoaded: function ({
  38. detail
  39. }) {
  40. console.log('assets loaded', detail.value);
  41. this.setData({
  42. loaded: true
  43. });
  44. },
  45. handleARReady: function ({
  46. detail
  47. }) {
  48. console.log('arReady');
  49. this.setData({
  50. arReady: true
  51. })
  52. },
  53. handleItem1Loaded({ detail }) {
  54. const el = detail.value.target;
  55. const animator = el.getComponent("animator");
  56. this.animator1 = animator
  57. console.log('animator1', animator)
  58. const gltf = el.getComponent("gltf");
  59. this.bgGltf = gltf;
  60. this.sunMeshes = this.resolveSunMeshesFromBG(gltf);
  61. this.setData({ sunReady: !!(this.sunMeshes && this.sunMeshes.length) });
  62. if (this.sunShouldRun) this.startSunRotation();
  63. this.tigerMeshes = this.resolveTigerMeshesFromBG(gltf);
  64. this.setData({ tigerReady: !!(this.tigerMeshes && this.tigerMeshes.length) });
  65. if (this.tigerShouldRun && this.tigerStartRequested) this.scheduleTigerStart();
  66. },
  67. handleItem2Loaded({ detail }) {
  68. const el = detail.value.target;
  69. const animator = el.getComponent("animator");
  70. this.animator2 = animator;
  71. },
  72. handleARTrackerState1({
  73. detail
  74. }) {
  75. // 事件的值即为`ARTracker`实例
  76. const tracker = detail.value;
  77. // 获取当前状态和错误信息
  78. console.log('tracker', tracker)
  79. const {
  80. state,
  81. } = tracker;
  82. if (state == 2) {
  83. this.play()
  84. } else {
  85. this.pause()
  86. }
  87. },
  88. play() {
  89. if (!this.data.loaded) return
  90. this.sunShouldRun = true;
  91. this.startSunRotation();
  92. this.tigerShouldRun = true;
  93. this.tigerStartRequested = false;
  94. this.prepareTigerAudio();
  95. if (!this.data.isStartPlay1) {
  96. this.setData({
  97. isStartPlay1: true
  98. }, () => {
  99. this.playitem1Action()
  100. })
  101. }
  102. },
  103. pause() {
  104. this.sunShouldRun = false;
  105. this.stopSunRotation();
  106. this.tigerShouldRun = false;
  107. this.tigerStartRequested = false;
  108. this.stopTiger();
  109. },
  110. resolveSunMeshesFromBG(gltf) {
  111. if (!gltf || !this.scene) return [];
  112. const candidates = this.getSunNameCandidates();
  113. const uniqueCandidates = [];
  114. for (const name of candidates) {
  115. if (name && !uniqueCandidates.includes(name)) uniqueCandidates.push(name);
  116. }
  117. for (const name of uniqueCandidates) {
  118. if (typeof gltf.getPrimitivesByNodeName === 'function') {
  119. const meshes = gltf.getPrimitivesByNodeName(name);
  120. if (meshes && meshes.length) return meshes;
  121. }
  122. if (typeof gltf.getPrimitivesByMeshName === 'function') {
  123. const meshes = gltf.getPrimitivesByMeshName(name);
  124. if (meshes && meshes.length) return meshes;
  125. }
  126. }
  127. if (typeof gltf.getMeshes === 'function') {
  128. const meshes = gltf.getMeshes() || [];
  129. const meshNames = meshes.map(m => m && (m.name || m.el && m.el.name)).filter(Boolean);
  130. console.warn('sun mesh not found, available mesh names:', meshNames);
  131. } else {
  132. console.warn('sun mesh not found');
  133. }
  134. return [];
  135. },
  136. getSunNameCandidates() {
  137. const defaultCandidates = ['Sun', 'sun', 'SUN', '太阳', 'Taiyang', 'taiyang'];
  138. if (!this.scene) return defaultCandidates;
  139. const gltfAsset = this.scene.assets && this.scene.assets.getAsset && this.scene.assets.getAsset('gltf', 'bg');
  140. const jsonRaw = gltfAsset && gltfAsset.jsonRaw;
  141. if (!jsonRaw) return defaultCandidates;
  142. const names = [];
  143. const addIfMatch = (n) => {
  144. if (!n || typeof n !== 'string') return;
  145. if (/Sun/i.test(n) || n.includes('太阳')) names.push(n);
  146. };
  147. if (Array.isArray(jsonRaw.nodes)) {
  148. for (const node of jsonRaw.nodes) addIfMatch(node && node.name);
  149. }
  150. if (Array.isArray(jsonRaw.meshes)) {
  151. for (const mesh of jsonRaw.meshes) addIfMatch(mesh && mesh.name);
  152. }
  153. return names.length ? names.concat(defaultCandidates) : defaultCandidates;
  154. },
  155. startSunRotation() {
  156. if (!this.scene) return;
  157. if (!this.sunShouldRun) return;
  158. if (!this.sunMeshes || !this.sunMeshes.length) return;
  159. if (this.sunRotationTimer) return;
  160. this.sunFrameCount = 159;
  161. this.sunFrameIndex = this.sunFrameIndex || 1;
  162. this.sunTextureCacheLimit = 12;
  163. if (!this.sunTextureCache) this.sunTextureCache = new Map();
  164. if (!this.sunTextureQueue) this.sunTextureQueue = [];
  165. this.updateSunFrame();
  166. this.sunRotationTimer = setInterval(() => this.updateSunFrame(), 80);
  167. },
  168. stopSunRotation() {
  169. if (this.sunRotationTimer) {
  170. clearInterval(this.sunRotationTimer);
  171. this.sunRotationTimer = null;
  172. }
  173. this.sunFrameLoading = false;
  174. if (this.scene && this.scene.assets && this.scene.assets.releaseAsset && this.sunTextureQueue) {
  175. for (const assetId of this.sunTextureQueue) {
  176. this.scene.assets.releaseAsset('texture', assetId);
  177. }
  178. }
  179. this.sunTextureCache = null;
  180. this.sunTextureQueue = null;
  181. },
  182. async updateSunFrame() {
  183. if (this.sunFrameLoading) return;
  184. if (!this.scene || !this.sunMeshes || !this.sunMeshes.length) return;
  185. if (!this.sunShouldRun) return;
  186. this.sunFrameLoading = true;
  187. try {
  188. const frame = this.sunFrameIndex;
  189. this.sunFrameIndex = frame >= this.sunFrameCount ? 1 : frame + 1;
  190. const frameStr = String(frame).padStart(3, '0');
  191. const assetId = `sun-${frameStr}`;
  192. const src = `https://ossxiaoan.4dage.com/hq-eduction-vr/sun/Sun_${frameStr}.png`;
  193. let texture = this.sunTextureCache && this.sunTextureCache.get(assetId);
  194. if (!texture) {
  195. const result = await this.scene.assets.loadAsset({ type: 'texture', assetId, src });
  196. texture = result && result.value;
  197. if (texture) {
  198. if (this.sunTextureCache) this.sunTextureCache.set(assetId, texture);
  199. if (this.sunTextureQueue) this.sunTextureQueue.push(assetId);
  200. while (this.sunTextureQueue && this.sunTextureQueue.length > this.sunTextureCacheLimit) {
  201. const oldAssetId = this.sunTextureQueue.shift();
  202. if (oldAssetId) {
  203. this.scene.assets.releaseAsset('texture', oldAssetId);
  204. if (this.sunTextureCache) this.sunTextureCache.delete(oldAssetId);
  205. }
  206. }
  207. }
  208. }
  209. if (texture) {
  210. for (const mesh of this.sunMeshes) {
  211. if (mesh && mesh.material && typeof mesh.material.setTexture === 'function') {
  212. mesh.material.setTexture('u_baseColorMap', texture);
  213. }
  214. }
  215. }
  216. } catch (e) {
  217. console.warn('updateSunFrame failed', e);
  218. } finally {
  219. this.sunFrameLoading = false;
  220. }
  221. },
  222. resolveTigerMeshesFromBG(gltf) {
  223. if (!gltf || !this.scene) return [];
  224. const candidates = this.getTigerNameCandidates();
  225. const uniqueCandidates = [];
  226. for (const name of candidates) {
  227. if (name && !uniqueCandidates.includes(name)) uniqueCandidates.push(name);
  228. }
  229. for (const name of uniqueCandidates) {
  230. if (typeof gltf.getPrimitivesByNodeName === 'function') {
  231. const meshes = gltf.getPrimitivesByNodeName(name);
  232. if (meshes && meshes.length) return meshes;
  233. }
  234. if (typeof gltf.getPrimitivesByMeshName === 'function') {
  235. const meshes = gltf.getPrimitivesByMeshName(name);
  236. if (meshes && meshes.length) return meshes;
  237. }
  238. }
  239. if (typeof gltf.getMeshes === 'function') {
  240. const meshes = gltf.getMeshes() || [];
  241. const meshNames = meshes.map(m => m && (m.name || m.el && m.el.name)).filter(Boolean);
  242. console.warn('tiger mesh not found, available mesh names:', meshNames);
  243. } else {
  244. console.warn('tiger mesh not found');
  245. }
  246. return [];
  247. },
  248. getTigerNameCandidates() {
  249. const defaultCandidates = ['Tiger', 'tiger', 'TIGER', '老虎', '虎', 'Laohu', 'laohu', 'hu'];
  250. if (!this.scene) return defaultCandidates;
  251. const gltfAsset = this.scene.assets && this.scene.assets.getAsset && this.scene.assets.getAsset('gltf', 'bg');
  252. const jsonRaw = gltfAsset && gltfAsset.jsonRaw;
  253. if (!jsonRaw) return defaultCandidates;
  254. const names = [];
  255. const addIfMatch = (n) => {
  256. if (!n || typeof n !== 'string') return;
  257. if (/tiger/i.test(n) || /laohu/i.test(n) || n.includes('虎')) names.push(n);
  258. };
  259. if (Array.isArray(jsonRaw.nodes)) {
  260. for (const node of jsonRaw.nodes) addIfMatch(node && node.name);
  261. }
  262. if (Array.isArray(jsonRaw.meshes)) {
  263. for (const mesh of jsonRaw.meshes) addIfMatch(mesh && mesh.name);
  264. }
  265. return names.length ? names.concat(defaultCandidates) : defaultCandidates;
  266. },
  267. scheduleTigerStart() {
  268. if (!this.scene) return;
  269. if (!this.tigerShouldRun) return;
  270. if (!this.tigerStartRequested) return;
  271. if (this.tigerCompleted) return;
  272. if (this.tigerRotationTimer) return;
  273. if (!this.tigerMeshes || !this.tigerMeshes.length) return;
  274. if (this.tigerAppearTimer) return;
  275. this.tigerAppearTimer = setInterval(() => {
  276. if (!this.tigerShouldRun || this.tigerCompleted) {
  277. this.stopTigerAppearWatch();
  278. return;
  279. }
  280. const visibleMeshes = this.getVisibleTigerMeshes();
  281. if (!visibleMeshes.length) return;
  282. this.stopTigerAppearWatch();
  283. this.tigerTargetMeshes = visibleMeshes;
  284. this.startTigerAudio();
  285. this.startTigerAnimation();
  286. }, 100);
  287. },
  288. stopTigerAppearWatch() {
  289. if (!this.tigerAppearTimer) return;
  290. clearInterval(this.tigerAppearTimer);
  291. this.tigerAppearTimer = null;
  292. },
  293. isTigerVisible() {
  294. return this.getVisibleTigerMeshes().length > 0;
  295. },
  296. getVisibleTigerMeshes() {
  297. if (!this.tigerMeshes || !this.tigerMeshes.length) return [];
  298. const visible = [];
  299. for (const mesh of this.tigerMeshes) {
  300. const el = mesh && mesh.el;
  301. if (!el || typeof el.getComponent !== 'function') continue;
  302. try {
  303. const transform = el.getComponent('transform');
  304. const scale = transform && transform.scale;
  305. if (!scale) continue;
  306. if (typeof scale === 'string') {
  307. const parts = scale.split(/\s+/).map(Number);
  308. const maxV = Math.max(...parts.filter(n => Number.isFinite(n)));
  309. if (Number.isFinite(maxV) && maxV > 0.001) visible.push(mesh);
  310. continue;
  311. }
  312. if (typeof scale === 'object') {
  313. const sx = typeof scale.x === 'number' ? scale.x : undefined;
  314. const sy = typeof scale.y === 'number' ? scale.y : undefined;
  315. const sz = typeof scale.z === 'number' ? scale.z : undefined;
  316. const maxV = Math.max(sx || 0, sy || 0, sz || 0);
  317. if (maxV > 0.001) visible.push(mesh);
  318. }
  319. } catch (e) {
  320. }
  321. }
  322. return visible;
  323. },
  324. startTigerAnimation() {
  325. if (!this.scene) return;
  326. if (!this.tigerShouldRun) return;
  327. if (!this.tigerMeshes || !this.tigerMeshes.length) return;
  328. if (this.tigerCompleted) return;
  329. if (this.tigerRotationTimer) return;
  330. this.tigerFrameStart = 1;
  331. this.tigerFrameEnd = 460;
  332. this.tigerFrameCount = 460;
  333. const skipFrames = 38;
  334. this.tigerPlayedFrames = Math.min(skipFrames, this.tigerFrameCount);
  335. this.tigerTextureCacheLimit = 12;
  336. if (!this.tigerTextureCache) this.tigerTextureCache = new Map();
  337. if (!this.tigerTextureQueue) this.tigerTextureQueue = [];
  338. this.updateTigerFrame();
  339. const intervalMs = this.getTigerFrameIntervalMs();
  340. this.tigerRotationTimer = setInterval(() => this.updateTigerFrame(), intervalMs);
  341. },
  342. getTigerFrameIntervalMs() {
  343. const durationMs = Number.isFinite(this.tigerAudioDurationMs) && this.tigerAudioDurationMs > 0
  344. ? this.tigerAudioDurationMs
  345. : 46000;
  346. const frameCount = typeof this.tigerFrameCount === 'number' && this.tigerFrameCount > 0 ? this.tigerFrameCount : 460;
  347. const raw = Math.round(durationMs / frameCount);
  348. return Math.min(500, Math.max(16, raw));
  349. },
  350. stopTiger() {
  351. this.stopTigerAppearWatch();
  352. if (this.tigerRotationTimer) {
  353. clearInterval(this.tigerRotationTimer);
  354. this.tigerRotationTimer = null;
  355. }
  356. this.tigerFrameLoading = false;
  357. this.tigerTargetMeshes = null;
  358. if (this.scene && this.scene.assets && this.scene.assets.releaseAsset && this.tigerTextureQueue) {
  359. for (const assetId of this.tigerTextureQueue) {
  360. if (assetId === this.tigerLastAssetId) continue;
  361. this.scene.assets.releaseAsset('texture', assetId);
  362. }
  363. }
  364. this.tigerTextureCache = null;
  365. this.tigerTextureQueue = null;
  366. this.stopTigerAudio();
  367. },
  368. async updateTigerFrame() {
  369. if (this.tigerFrameLoading) return;
  370. if (!this.scene || !this.tigerMeshes || !this.tigerMeshes.length) return;
  371. if (!this.tigerShouldRun) return;
  372. if (this.tigerCompleted) return;
  373. this.tigerFrameLoading = true;
  374. try {
  375. const frameCount = typeof this.tigerFrameCount === 'number' && this.tigerFrameCount > 0 ? this.tigerFrameCount : 460;
  376. const durationMs = Number.isFinite(this.tigerAudioDurationMs) && this.tigerAudioDurationMs > 0
  377. ? this.tigerAudioDurationMs
  378. : 46000;
  379. const played = this.tigerPlayedFrames || 0;
  380. let desiredPlayed = played + 1;
  381. const audioCtx = this.tigerAudioCtx;
  382. if (audioCtx && this.tigerAudioStarted) {
  383. const currentTime = Number(audioCtx.currentTime);
  384. if (Number.isFinite(currentTime) && currentTime >= 0) {
  385. const p = Math.floor((currentTime * 1000 / durationMs) * frameCount) + 1;
  386. desiredPlayed = Math.max(desiredPlayed, p);
  387. }
  388. }
  389. if (desiredPlayed <= played) return;
  390. if (desiredPlayed >= frameCount) desiredPlayed = frameCount;
  391. if (played >= frameCount) {
  392. this.completeTigerAnimation();
  393. return;
  394. }
  395. const start = typeof this.tigerFrameStart === 'number' ? this.tigerFrameStart : 1;
  396. const end = typeof this.tigerFrameEnd === 'number' ? this.tigerFrameEnd : frameCount;
  397. const rangeLen = Math.max(1, end - start + 1);
  398. const frameNo = start + ((desiredPlayed - 1) % rangeLen);
  399. this.tigerPlayedFrames = desiredPlayed;
  400. const frameStr = String(frameNo).padStart(3, '0');
  401. const assetId = `tigerx-${frameStr}`;
  402. const src = `https://ossxiaoan.4dage.com/hq-eduction-vr/tiger/Tigerx_${frameStr}.png`;
  403. let texture = this.tigerTextureCache && this.tigerTextureCache.get(assetId);
  404. if (!texture) {
  405. const result = await this.scene.assets.loadAsset({ type: 'texture', assetId, src });
  406. texture = result && result.value;
  407. if (texture) {
  408. if (this.tigerTextureCache) this.tigerTextureCache.set(assetId, texture);
  409. if (this.tigerTextureQueue) this.tigerTextureQueue.push(assetId);
  410. while (this.tigerTextureQueue && this.tigerTextureQueue.length > this.tigerTextureCacheLimit) {
  411. const oldAssetId = this.tigerTextureQueue.shift();
  412. if (oldAssetId) {
  413. this.scene.assets.releaseAsset('texture', oldAssetId);
  414. if (this.tigerTextureCache) this.tigerTextureCache.delete(oldAssetId);
  415. }
  416. }
  417. }
  418. }
  419. if (texture) {
  420. this.tigerLastAssetId = assetId;
  421. const targets = (this.tigerTargetMeshes && this.tigerTargetMeshes.length) ? this.tigerTargetMeshes : this.tigerMeshes;
  422. for (const mesh of targets) {
  423. if (mesh && mesh.material && typeof mesh.material.setTexture === 'function') {
  424. mesh.material.setTexture('u_baseColorMap', texture);
  425. }
  426. }
  427. }
  428. if (this.tigerPlayedFrames >= this.tigerFrameCount) {
  429. this.completeTigerAnimation();
  430. }
  431. } catch (e) {
  432. console.warn('updateTigerFrame failed', e);
  433. } finally {
  434. this.tigerFrameLoading = false;
  435. }
  436. },
  437. completeTigerAnimation() {
  438. if (this.tigerRotationTimer) {
  439. clearInterval(this.tigerRotationTimer);
  440. this.tigerRotationTimer = null;
  441. }
  442. this.tigerCompleted = true;
  443. },
  444. prepareTigerAudio() {
  445. if (this.tigerAudioCtx || this.tigerAudioPreparing) return;
  446. const url = 'https://ossxiaoan.4dage.com/hq-eduction-vr/tiger/tiger.mp3';
  447. this.tigerAudioPrepared = false;
  448. this.tigerAudioStartPending = !!this.tigerAudioStartPending;
  449. this.tigerAudioStarted = false;
  450. this.tigerAudioPreparing = true;
  451. const createAudioCtx = (src) => {
  452. const audioCtx = wx.createInnerAudioContext();
  453. audioCtx.src = src;
  454. audioCtx.loop = false;
  455. audioCtx.volume = 0;
  456. audioCtx.onCanplay(() => {
  457. if (this.tigerAudioPrepared) return;
  458. this.tigerAudioPrepared = true;
  459. if (this.tigerAudioStarted) return;
  460. const updateDuration = () => {
  461. if (!this.tigerAudioCtx) return;
  462. const d = Number(audioCtx.duration);
  463. if (Number.isFinite(d) && d > 0) this.tigerAudioDurationMs = Math.round(d * 1000);
  464. };
  465. updateDuration();
  466. setTimeout(updateDuration, 300);
  467. try {
  468. audioCtx.volume = 0;
  469. } catch (e) {
  470. }
  471. try {
  472. audioCtx.play();
  473. } catch (e) {
  474. }
  475. setTimeout(() => {
  476. if (!this.tigerAudioCtx) return;
  477. if (this.tigerAudioStarted) return;
  478. try {
  479. audioCtx.pause();
  480. } catch (e) {
  481. }
  482. try {
  483. if (Number(audioCtx.currentTime) > 0.1) audioCtx.seek(0);
  484. } catch (e) {
  485. }
  486. if (this.tigerAudioStartPending) this.startTigerAudio();
  487. }, 200);
  488. });
  489. audioCtx.onEnded(() => {
  490. this.stopTigerAudio();
  491. this.completeTigerAnimation();
  492. });
  493. this.tigerAudioCtx = audioCtx;
  494. this.tigerAudioPreparing = false;
  495. try {
  496. audioCtx.play();
  497. } catch (e) {
  498. }
  499. };
  500. if (this.tigerAudioTempPath) {
  501. createAudioCtx(this.tigerAudioTempPath);
  502. return;
  503. }
  504. wx.downloadFile({
  505. url,
  506. success: (res) => {
  507. const tempPath = res && res.statusCode === 200 ? res.tempFilePath : '';
  508. if (tempPath) this.tigerAudioTempPath = tempPath;
  509. createAudioCtx(tempPath || url);
  510. },
  511. fail: () => {
  512. createAudioCtx(url);
  513. }
  514. });
  515. },
  516. startTigerAudio() {
  517. if (this.tigerAudioStarted) return;
  518. if (!this.tigerAudioCtx) {
  519. this.tigerAudioStartPending = true;
  520. this.prepareTigerAudio();
  521. }
  522. if (!this.tigerAudioCtx) return;
  523. if (this.tigerAudioStarted) return;
  524. const audioCtx = this.tigerAudioCtx;
  525. const startOffsetSec = 2;
  526. const startNow = () => {
  527. if (!this.tigerAudioCtx) return;
  528. if (this.tigerAudioStarted) return;
  529. try {
  530. audioCtx.volume = 1;
  531. } catch (e) {
  532. }
  533. try {
  534. const t = Number(audioCtx.currentTime);
  535. if (!Number.isFinite(t) || Math.abs(t - startOffsetSec) > 0.2) audioCtx.seek(startOffsetSec);
  536. } catch (e) {
  537. }
  538. try {
  539. audioCtx.play();
  540. this.tigerAudioStarted = true;
  541. } catch (e) {
  542. this.tigerAudioStarted = false;
  543. }
  544. };
  545. if (this.tigerAudioPrepared) {
  546. this.tigerAudioStartPending = false;
  547. startNow();
  548. return;
  549. }
  550. this.tigerAudioStartPending = true;
  551. startNow();
  552. },
  553. stopTigerAudio() {
  554. if (!this.tigerAudioCtx) return;
  555. this.tigerAudioCtx.stop();
  556. this.tigerAudioCtx.destroy();
  557. this.tigerAudioCtx = null;
  558. this.tigerAudioPrepared = false;
  559. this.tigerAudioStartPending = false;
  560. this.tigerAudioStarted = false;
  561. this.tigerAudioPreparing = false;
  562. this.tigerAudioDurationMs = null;
  563. },
  564. playitem1Action() {
  565. if (!this.animator1 || !this.animator2) return;
  566. console.log('start animator1');
  567. this.animator1.play('All Animations', {
  568. loop: 0
  569. });
  570. setTimeout(() => {
  571. console.log('start animator2');
  572. this.animator2.pause();
  573. const duration = 1500;
  574. const startTime = Date.now();
  575. const startScale = 0;
  576. const endScale = 0.38;
  577. const startPX = -0.1
  578. const endPX = 0
  579. const startPY = -0.5
  580. const endPY = 0
  581. const startPZ = -0.05
  582. const endPZ = 0
  583. const step = () => {
  584. const now = Date.now();
  585. let t = (now - startTime) / duration;
  586. if (t > 1) t = 1;
  587. const s = startScale + (endScale - startScale) * t;
  588. const scaleStr = `${s} ${s} ${s}`;
  589. const p = `${startPX + (endPX - startPX) * t} ${startPY + (endPY - startPY) * t} ${startPZ + (endPZ - startPZ) * t}`;
  590. if (t >= 0.5 && !this.isStartPlay2) {
  591. this.isStartPlay2 = true;
  592. this.animator2.play('All Animations', {
  593. loop: 0
  594. });
  595. }
  596. this.setData({
  597. adlScale: scaleStr,
  598. adlPos: p
  599. });
  600. if (t < 1) {
  601. setTimeout(step, 16); // 60fps
  602. } else {
  603. const audioUrl = 'https://houseoss.4dkankan.com/project/hq-eduction-vr/public/%E5%AE%89%E5%BE%B7%E7%83%88.mp3';
  604. if (!this.audioCtx) {
  605. const audioCtx = wx.createInnerAudioContext();
  606. audioCtx.src = audioUrl;
  607. audioCtx.play();
  608. audioCtx.onEnded(() => {
  609. const hideDuration = 1000;
  610. const hideStartTime = Date.now();
  611. const startScaleHide = 0.38;
  612. const endScaleHide = 0;
  613. const hideStep = () => {
  614. const now = Date.now();
  615. let t = (now - hideStartTime) / hideDuration;
  616. if (t > 1) t = 1;
  617. const s = startScaleHide + (endScaleHide - startScaleHide) * t;
  618. const scaleStr = `${s} ${s} ${s}`;
  619. this.setData({
  620. adlScale: scaleStr
  621. });
  622. if (t < 1) {
  623. setTimeout(hideStep, 16);
  624. } else {
  625. this.animator2 = null;
  626. if (this.audioCtx) {
  627. this.audioCtx.destroy();
  628. this.audioCtx = null;
  629. }
  630. this.tigerStartRequested = true;
  631. this.scheduleTigerStart();
  632. }
  633. };
  634. hideStep();
  635. });
  636. }
  637. }
  638. };
  639. this.setData({
  640. adlScale: '0 0 0'
  641. });
  642. step();
  643. }, 1500);
  644. }
  645. }
  646. })