diff --git a/js/scene/SceneManager.js b/js/scene/SceneManager.js index 86be696..a7cab50 100644 --- a/js/scene/SceneManager.js +++ b/js/scene/SceneManager.js @@ -30,6 +30,10 @@ export class SceneManager { this.earthModel = null; this.transition = null; + // 动画控制 + this.animationFrameId = null; + this.introTimeline = null; + this.init(); } @@ -97,12 +101,15 @@ export class SceneManager { startIntroSequence(uiElements) { const animConfig = CONFIG.animation.intro; - const tl = gsap.timeline({ + // 保存 timeline 引用,以便在 dispose 时清理 + this.introTimeline = gsap.timeline({ onComplete: () => { this.isIntro = false; // 动画结束,允许交互 } }); + const tl = this.introTimeline; + // A. 摄像机缓慢推进 (从 z=100 -> z=16) tl.to(this.camera.position, { z: CONFIG.scene.camera.defaultZ, @@ -279,7 +286,7 @@ export class SceneManager { // 动画循环 animate() { - requestAnimationFrame(() => this.animate()); + this.animationFrameId = requestAnimationFrame(() => this.animate()); // 如果不在转场中 if (!this.transition || !this.transition.isActive()) { @@ -299,6 +306,31 @@ export class SceneManager { // 销毁场景 dispose() { + // 停止动画循环 + if (this.animationFrameId) { + cancelAnimationFrame(this.animationFrameId); + this.animationFrameId = null; + } + + // 杀掉所有正在运行的 GSAP 动画 + if (this.introTimeline) { + this.introTimeline.kill(); + this.introTimeline = null; + } + + // 杀掉转场相关的 GSAP 动画(杀掉所有针对相机、地球等对象的动画) + if (this.camera) { + gsap.killTweensOf(this.camera.position); + } + if (this.earthModel) { + const earthGroup = this.earthModel.getGroup(); + const clouds = this.earthModel.getClouds(); + const atmosphere = this.earthModel.getAtmosphere(); + if (earthGroup) gsap.killTweensOf(earthGroup.rotation); + if (clouds) gsap.killTweensOf(clouds.material); + if (atmosphere) gsap.killTweensOf(atmosphere.material); + } + // 移除事件监听器,防止内存泄漏和重复触发 if (this.eventHandlers) { window.removeEventListener('mousemove', this.eventHandlers.mouseMove); @@ -308,6 +340,12 @@ export class SceneManager { window.removeEventListener('resize', this.eventHandlers.resize); } + // 清理转场动画 + if (this.transition) { + this.transition.dispose(); + this.transition = null; + } + if (this.starSystem) this.starSystem.dispose(); if (this.earthModel) this.earthModel.dispose(); if (this.renderer) { diff --git a/js/scene/Transition.js b/js/scene/Transition.js index 61177d6..da7fcef 100644 --- a/js/scene/Transition.js +++ b/js/scene/Transition.js @@ -11,6 +11,7 @@ export class Transition { this.uiElements = uiElements; // { uiLayer, hint, speedLines, cloudFog } this.onComplete = onComplete; this.isTransitioning = false; + this.timeline = null; // 保存 timeline 引用以便清理 } // 触发超空间跳跃转场 @@ -29,14 +30,16 @@ export class Transition { const clouds = this.earthModel.getClouds(); const atmosphere = this.earthModel.getAtmosphere(); - // 创建GSAP时间线 - const tl = gsap.timeline({ + // 创建GSAP时间线(保存引用以便清理) + this.timeline = gsap.timeline({ onComplete: () => { this.isTransitioning = false; if (this.onComplete) this.onComplete(); } }); + const tl = this.timeline; + // 转场配置 const warpConfig = CONFIG.warp; const transConfig = CONFIG.animation.transition; @@ -101,4 +104,13 @@ export class Transition { isActive() { return this.isTransitioning; } + + // 清理转场动画 + dispose() { + if (this.timeline) { + this.timeline.kill(); + this.timeline = null; + } + this.isTransitioning = false; + } }