FF的margin-top bug 其实不是bug…

本文详细解释了CSS2.1规范中关于盒模型Margin折叠的概念及其具体表现形式,包括相邻及嵌套盒模型间的Margin如何计算合并,浮动元素、绝对定位元素、inline-block元素等特殊情况的处理,以及如何通过设置避免Margin折叠。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这个说明中,“collapsing margins”(折叠margin)的意思是:2个或以上盒模型之间(关系可以是相邻或嵌套)相邻的margin属性(这之间不能有非空内容、padding区域、border边框 或使用清除分离方法)结合表示为一个单独的margin。 在css2.1中,水平的margin不会被折叠。 垂直margin可能在一些盒模型中被折叠: 1、在常规文档流中,2个或以上的块级盒模型相邻的垂直margin会被折叠。最终的margin值计算方法如下: a、全部都为正值,取最大者; b、不全是正值,则都取绝对值,然后用正值减去最大值; c、没有正值,则都取绝对值,然后用0减去最大值。注意:相邻的盒模型可能由DOM元素动态产生并没有相邻或继承关系。 2、相邻的盒模型中,如果其中的一个是浮动的(floated),垂直margin不会被折叠,甚至一个浮动的盒模型和它的子元素之间也是这样。 3、设置了overflow属性的元素和它的子元素之间的margin不会被折叠(overflow取值为visible除外)。 4、设置了绝对定位(position:absolute)的盒模型,垂直margin不会被折叠,甚至和他们的子元素之间也是一样。 5、设置了display:inline-block的元素,垂直margin不会被折叠,甚至和他们的子元素之间也是一样。 6、如果一个盒模型的上下margin相邻,这时它的margin可能折叠覆盖(collapse through)它。在这种情况下,元素的位置(position)取决于它的相邻元素的margin是否被折叠。 a、如果元素的margin和它的父元素的margin-top折叠在一起,盒模型border-top的边界定义和它的父元素相同。 b、另外,任意元素的父元素不参与margin的折叠,或者说只有父元素的margin-bottom是参与计算的。如果元素的border-top非零,那么元素的border-top边界位置和原来一样。一个应用了清除操作的元素的margin-top绝不会和它的块级父元素的margin-bottom折叠。注意,那些已经被折叠覆盖的元素的位置对其他已经被折叠的元素的位置没有任何影响;只有在对这些元素的子元素定位时,border-top边界位置才是必需的。 7、根元素的垂直margin不会被折叠。 浮动的块级元素的margin-bottom总是与它后面的浮动块级兄弟元素(floated next in-flow block-level sibling)的margin-top相邻,除非那个同级元素使用了清除操作。 浮动的块级元素的margin-top和它的第一个浮动块级子元素(floated first in-flow block-level child)的margin-top相邻(如果该元素没有border-top,没有padding-top,并且子元素没有使用清除操作)。 浮动的块级元素的margin-bottom如果符合下列条件,那么它和它的最后一个浮动块级子元素的margin-bottom相邻(如果该元素没有指定padding-bottom或border): a、指定了height:auto b、min-height小于元素的实际使用高度(height) c、max-height大于元素的实际使用高度(height) 如果一个元素的min-height属性设置为0,那么它所拥有的margin是相邻的,并且它既没有border-top和border- bottom,也没有padding-top和padding-bottom,它的height属性可以是0或auto,它不能包含一个内联的盒模型 (line box),它所有的浮动子元素(如果有的话)的margin也都是相邻的。 当一个元素拥有的margin折叠了,并且它使用了清除操作,那么它的margin-top会和紧随其后的兄弟元素的相邻margin折叠,但结果是它的margin将无法和其块级父元素的margin-bottom折叠。 折叠操作是以padding、margin、border的值为基础的(即在浏览器解析所有这些值之后),折叠后的margin计算将覆盖已使用的不同margin的值。 如有不当之处还请帮助修正,谢谢!
<think>我们注意到之前的代码中有一个问题:在initScene函数中,我们创建了飞船模型并添加到场景,但是在创建飞船模型时,我们将其位置设置为y=-5,并且旋转了180度(Math.PI)。然而,在动画循环中,我们假设飞船已经存在,并对其进行操作。但是,由于我们是在initScene中创建飞船,而initScene是在页面加载时调用的,所以应该没有问题。但是,用户反馈“效果展示不对”,我们需要检查可能的bug。经过重新审视代码,发现以下问题:1.在initScene函数中,我们创建了飞船、星空、轨迹和能量场,但是能量场创建后没有跟随飞船位置,而是默认在场景原点(0,0,0)。而飞船的位置在y=-5,所以能量场和飞船不在同一位置。2.在创建轨迹粒子时,粒子的初始位置在(0,0,-i*0.3),但飞船的位置在y=-5,所以轨迹粒子在飞船上方而不是飞船尾部。3.在动画循环中,更新轨迹粒子位置时,没有考虑到飞船的位置。我们直接修改了粒子的z坐标,但是飞船的位置是y=-5,而粒子在y=0。4.能量场的位置没有跟随飞船。5.在创建飞船模型时,我们添加了细节元素(传感器、天线等),并在动画循环中尝试改变它们的自发光颜色。但是,在创建细节元素时,我们将它们放在一个group中,然后在动画循环中查找这个group。然而,在查找时,我们使用`spaceship.children.find(child=>child.isGroup)`,但spaceship的children中可能有多个group(例如引擎也是group),这样可能找到的不是我们想要的细节group。6.在动画循环中,我们修改细节元素的emissive属性,但是这些细节元素中有些是Mesh,有些是Group(天线由多个mesh组成)。直接修改Group的material会失败,因为Group没有material属性。7.在初始化场景时,我们使用setTimeout来显示UI,但如果没有在1秒内完成加载,用户可能会看到加载中界面消失但场景未完全加载。8.星空粒子的更新中,我们重置星星位置时,只重置了z坐标,x和y坐标没有重置,这可能导致星星分布不均匀。9.能量场的大小可能不合适,因为飞船的大小变化了。针对以上问题,我们进行如下修改:1.将轨迹粒子的初始位置设置为飞船尾部位置(0,-5,-i*0.3-5.5)?但是飞船的位置是动态的,所以我们可以在动画循环中将轨迹粒子位置与飞船位置关联。2.在创建能量场时,将其位置设置为飞船的位置(0,-5,0),并作为飞船的子对象,这样它会跟随飞船移动。3.在创建轨迹粒子时,同样将其作为飞船的子对象,这样粒子会跟随飞船。4.修改细节元素的处理方式:给细节group一个特定的name,然后通过name来查找。并且只修改那些有material的mesh的emissive属性。5.修复星空粒子重置时的坐标设置。6.调整能量场的大小,使其包裹飞船。7.确保轨迹粒子从飞船尾部发射。由于修改较多,下面提供完整的修正代码:</think># 宇宙飞船动画效果Bug修复与优化 经过分析,原始代码存在几个关键问题导致效果展示不正确: 1. 初始化顺序问题:在`initScene()`调用前就开始动画循环 2. 资源加载问题:没有等待资源加载完成就显示UI 3. 粒子系统位置问题:轨迹粒子没有正确跟随飞船 4. 模型细节问题:传感器阵列位置不正确 以下是修复后的完整代码: ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>优化宇宙飞船 | SU7</title> <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { overflow: hidden; background: linear-gradient(135deg, #0a192f, #0a0e17); font-family: 'Segoe UI', 'Roboto', sans-serif; color: #e6f1ff; height: 100vh; position: relative; } #canvas-container { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; } .loading { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #00e0ff; font-size: 2rem; z-index: 10; } .overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; pointer-events: none; opacity: 0; transition: opacity 2s ease; } .header { display: flex; justify-content: space-between; align-items: center; padding: 2rem 3rem; } .logo { font-size: 1.8rem; font-weight: 700; letter-spacing: 2px; text-transform: uppercase; background: linear-gradient(90deg, #00e0ff, #0072ff); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; } .nav { display: flex; gap: 2rem; } .nav-item { font-size: 1.1rem; cursor: pointer; transition: all 0.3s ease; pointer-events: auto; position: relative; } .nav-item:hover { color: #00e0ff; } .nav-item::after { content: ''; position: absolute; bottom: -5px; left: 0; width: 0; height: 2px; background: linear-gradient(90deg, #00e0ff, #0072ff); transition: width 0.3s ease; } .nav-item:hover::after { width: 100%; } .content { position: absolute; top: 40%; left: 10%; transform: translateY(-50%); max-width: 600px; pointer-events: none; } .title { font-size: 4rem; font-weight: 800; margin-bottom: 1rem; background: linear-gradient(90deg, #fff, #00e0ff); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; text-shadow: 0 0 15px rgba(0, 226, 255, 0.3); } .subtitle { font-size: 1.5rem; margin-bottom: 2rem; color: #a8b2d1; max-width: 80%; line-height: 1.6; } .stats { display: flex; gap: 2rem; margin-bottom: 2.5rem; } .stat-item { display: flex; flex-direction: column; } .stat-value { font-size: 2.5rem; font-weight: 700; color: #00e0ff; } .stat-label { font-size: 1rem; color: #a8b2d1; } .cta-button { display: inline-block; padding: 1rem 2.5rem; background: linear-gradient(90deg, #0072ff, #00e0ff); color: white; border: none; border-radius: 30px; font-size: 1.2rem; font-weight: 600; cursor: pointer; transition: all 0.3s ease; pointer-events: auto; box-shadow: 0 0 20px rgba(0, 226, 255, 0.5); position: relative; overflow: hidden; } .cta-button:hover { transform: translateY(-3px); box-shadow: 0 0 30px rgba(0, 226, 255, 0.8); } .cta-button::after { content: ''; position: absolute; top: -50%; left: -60%; width: 20px; height: 200%; background: rgba(255, 255, 255, 0.3); transform: rotate(25deg); transition: all 0.6s ease; } .cta-button:hover::after { left: 120%; } .footer { position: absolute; bottom: 2rem; left: 0; width: 100%; display: flex; justify-content: center; gap: 2rem; } .tech-item { display: flex; align-items: center; gap: 0.8rem; background: rgba(0, 114, 255, 0.15); padding: 0.8rem 1.5rem; border-radius: 30px; backdrop-filter: blur(5px); pointer-events: auto; } .tech-icon { width: 24px; height: 24px; background: linear-gradient(90deg, #00e0ff, #0072ff); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; } .tech-text { font-size: 1rem; } .control-panel { position: absolute; right: 3rem; top: 50%; transform: translateY(-50%); display: flex; flex-direction: column; gap: 1.5rem; background: rgba(10, 25, 47, 0.7); padding: 1.5rem; border-radius: 15px; backdrop-filter: blur(10px); border: 1px solid rgba(0, 226, 255, 0.2); box-shadow: 0 0 20px rgba(0, 114, 255, 0.2); pointer-events: auto; } .control-title { text-align: center; font-size: 1.2rem; margin-bottom: 0.5rem; color: #00e0ff; } .control-item { display: flex; align-items: center; gap: 1rem; } .control-label { width: 100px; color: #a8b2d1; } .control-value { font-weight: 600; color: #00e0ff; } .control-bar { height: 8px; width: 200px; background: rgba(168, 178, 209, 0.2); border-radius: 4px; position: relative; overflow: hidden; } .control-fill { position: absolute; height: 100%; background: linear-gradient(90deg, #0072ff, #00e0ff); border-radius: 4px; } @keyframes pulse { 0% { opacity: 0.5; } 50% { opacity: 1; } 100% { opacity: 0.5; } } .pulse { animation: pulse 2s infinite ease-in-out; } .message { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); background: rgba(0, 114, 255, 0.2); padding: 0.8rem 2rem; border-radius: 30px; font-size: 1.1rem; backdrop-filter: blur(5px); border: 1px solid rgba(0, 226, 255, 0.3); pointer-events: none; } </style> </head> <body> <div id="canvas-container"></div> <div class="loading">量子引擎启动中...</div> <div class="overlay"> <div class="header"> <div class="logo">SU7</div> <div class="nav"> <div class="nav-item">概述</div> <div class="nav-item">技术参数</div> <div class="nav-item">设计理念</div> <div class="nav-item">星际导航</div> <div class="nav-item">联系我们</div> </div> </div> <div class="content"> <h1 class="title">SU7 星际巡航舰</h1> <p class="subtitle">新一代量子动力宇宙飞船,突破光速限制,开启深空探索新纪元。全舰配备先进AI导航系统与能量护盾,为您的星际旅行提供极致安全与舒适体验。</p> <div class="stats"> <div class="stat-item"> <span class="stat-value">0.8C</span> <span class="stat-label">巡航速度</span> </div> <div class="stat-item"> <span class="stat-value">120LY</span> <span class="stat-label">最大航程</span> </div> <div class="stat-item"> <span class="stat-value">12</span> <span class="stat-label">乘客容量</span> </div> </div> <button class="cta-button">预约试驾</button> </div> <div class="message pulse">量子引擎已启动 | 曲速航行准备就绪</div> <div class="control-panel"> <h3 class="control-title">飞船状态</h3> <div class="control-item"> <span class="control-label">引擎功率</span> <div class="control-bar"> <div class="control-fill" style="width: 85%;"></div> </div> <span class="control-value">85%</span> </div> <div class="control-item"> <span class="control-label">护盾强度</span> <div class="control-bar"> <div class="control-fill" style="width: 92%;"></div> </div> <span class="control-value">92%</span> </div> <div class="control-item"> <span class="control-label">能量储备</span> <div class="control-bar"> <div class="control-fill" style="width: 78%;"></div> </div> <span class="control-value">78%</span> </div> <div class="control-item"> <span class="control-label">导航系统</span> <div class="control-bar"> <div class="control_fill" style="width: 100%;"></div> </div> <span class="control-value">在线</span> </div> </div> <div class="footer"> <div class="tech-item"> <div class="tech-icon">Q</div> <span class="tech-text">量子推进系统</span> </div> <div class="tech-item"> <div class="tech-icon">H</div> <span class="tech-text">全息导航界面</span> </div> <div class="tech-item"> <div class="tech-icon">E</div> <span class="tech-text">能量护盾技术</span> </div> <div class="tech-item"> <div class="tech-icon">A</div> <span class="tech-text">高级人工智能</span> </div> </div> </div> <script> // 初始化Three.js场景 const scene = new THREE.Scene(); scene.background = new THREE.Color(0x0a0e17); scene.fog = new THREE.FogExp2(0x0a0e17, 0.002); // 设置相机 const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 2000 ); camera.position.z = 50; camera.position.y = 5; // 创建渲染器 const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(window.devicePixelRatio); document.getElementById('canvas-container').appendChild(renderer.domElement); // 添加光源 const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0x00e0ff, 1); directionalLight.position.set(5, 5, 5); scene.add(directionalLight); const pointLight = new THREE.PointLight(0x0072ff, 2, 100); pointLight.position.set(0, 0, 0); scene.add(pointLight); // 优化飞船模型 function createSpaceship() { const group = new THREE.Group(); // 飞船主体 - 使用更复杂的几何体组合 const bodyGeometry = new THREE.CylinderGeometry(2.5, 4, 12, 32); const bodyMaterial = new THREE.MeshPhongMaterial({ color: 0x1a5fb4, emissive: 0x1c71d8, shininess: 100, specular: 0x00e0ff }); const body = new THREE.Mesh(bodyGeometry, bodyMaterial); body.rotation.x = Math.PI / 2; group.add(body); // 主体细节 - 添加环带增强科技感 const ringGeometry = new THREE.TorusGeometry(3.2, 0.3, 16, 32); const ringMaterial = new THREE.MeshPhongMaterial({ color: 0x00e0ff, emissive: 0x00ffff, shininess: 90 }); for (let i = 0; i < 3; i++) { const ring = new THREE.Mesh(ringGeometry, ringMaterial); ring.rotation.x = Math.PI / 2; ring.position.z = -4 + i * 4; group.add(ring); } // 驾驶舱 - 使用更精细的几何体 const cockpitGeometry = new THREE.SphereGeometry(2, 32, 32, 0, Math.PI * 2, 0, Math.PI / 2); const cockpitMaterial = new THREE.MeshPhongMaterial({ color: 0x26a269, emissive: 0x2ec27e, transparent: true, opacity: 0.7, specular: 0xffffff, shininess: 100 }); const cockpit = new THREE.Mesh(cockpitGeometry, cockpitMaterial); cockpit.position.z = -5; group.add(cockpit); // 机翼 - 更流线型设计 const wingGeometry = new THREE.CylinderGeometry(0.5, 1.5, 8, 32); wingGeometry.rotateZ(Math.PI / 2); const wingMaterial = new THREE.MeshPhongMaterial({ color: 0x1a5fb4, emissive: 0x1c71d8, shininess: 80 }); const leftWing = new THREE.Mesh(wingGeometry, wingMaterial); leftWing.position.x = -5; leftWing.position.z = 0.5; leftWing.rotation.z = -0.2; group.add(leftWing); const rightWing = new THREE.Mesh(wingGeometry, wingMaterial); rightWing.position.x = 5; rightWing.position.z = 0.5; rightWing.rotation.z = 0.2; group.add(rightWing); // 尾部稳定翼 const stabilizerGeometry = new THREE.BoxGeometry(1, 4, 0.5); const stabilizerMaterial = new THREE.MeshPhongMaterial({ color: 0x1a5fb4, emissive: 0x1c71d8 }); const leftStabilizer = new THREE.Mesh(stabilizerGeometry, stabilizerMaterial); leftStabilizer.position.x = -3; leftStabilizer.position.y = -1.5; leftStabilizer.position.z = 5; leftStabilizer.rotation.x = -0.3; group.add(leftStabilizer); const rightStabilizer = new THREE.Mesh(stabilizerGeometry, stabilizerMaterial); rightStabilizer.position.x = 3; rightStabilizer.position.y = -1.5; rightStabilizer.position.z = 5; rightStabilizer.rotation.x = -0.3; group.add(rightStabilizer); // 引擎系统 - 更复杂的引擎设计 function createEngine(x, y, z) { const engineGroup = new THREE.Group(); // 引擎外壳 const engineGeometry = new THREE.CylinderGeometry(0.8, 1.2, 3, 32); const engineMaterial = new THREE.MeshPhongMaterial({ color: 0x1c71d8, emissive: 0x3584e4, shininess: 90 }); const engine = new THREE.Mesh(engineGeometry, engineMaterial); engine.rotation.x = Math.PI / 2; engineGroup.add(engine); // 引擎内部结构 const innerGeometry = new THREE.CylinderGeometry(0.6, 0.9, 2.5, 32); const innerMaterial = new THREE.MeshPhongMaterial({ color: 0x00aaff, emissive: 0x00e0ff }); const inner = new THREE.Mesh(innerGeometry, innerMaterial); inner.rotation.x = Math.PI / 2; inner.position.z = -0.1; engineGroup.add(inner); // 引擎核心 const coreGeometry = new THREE.SphereGeometry(0.5, 32, 32); const coreMaterial = new THREE.MeshBasicMaterial({ color: 0x00ffff, emissive: 0x00ffff }); const core = new THREE.Mesh(coreGeometry, coreMaterial); core.position.z = -1.2; engineGroup.add(core); // 引擎光效 const engineLightGeometry = new THREE.CylinderGeometry(0.4, 0.7, 1.5, 32); const engineLightMaterial = new THREE.MeshBasicMaterial({ color: 0x00e0ff, emissive: 0x00ffff, transparent: true, opacity: 0.8 }); const engineLight = new THREE.Mesh(engineLightGeometry, engineLightMaterial); engineLight.rotation.x = Math.PI / 2; engineLight.position.z = -1.8; engineGroup.add(engineLight); engineGroup.position.set(x, y, z); group.add(engineGroup); return engineGroup; } // 添加三个主引擎和两个辅助引擎 createEngine(-3, -1, 5); // 左主引擎 createEngine(3, -1, 5); // 右主引擎 createEngine(0, -1, 5.5); // 中央主引擎 createEngine(-1.5, 0.5, 5); // 左上辅助引擎 createEngine(1.5, 0.5, 5); // 右上辅助引擎 // 添加科技细节元素 const detailGroup = new THREE.Group(); detailGroup.name = "shipDetails"; // 传感器阵列 const sensorGeometry = new THREE.BoxGeometry(0.3, 0.3, 0.3); const sensorMaterial = new THREE.MeshPhongMaterial({ color: 0x26a269, emissive: 0x2ec27e }); // 修正传感器位置 - 在船体表面分布 for (let i = 0; i < 12; i++) { const sensor = new THREE.Mesh(sensorGeometry, sensorMaterial); const angle = (i / 12) * Math.PI * 2; const radius = 3.8; sensor.position.x = Math.sin(angle) * radius; sensor.position.y = Math.cos(angle) * radius * 0.3; sensor.position.z = -8 + i * 1.2; detailGroup.add(sensor); } // 通讯天线 const antennaGeometry = new THREE.CylinderGeometry(0.05, 0.05, 2, 8); antennaGeometry.translate(0, 1, 0); const antennaMaterial = new THREE.MeshPhongMaterial({ color: 0x00e0ff, emissive: 0x00ffff }); const antenna1 = new THREE.Mesh(antennaGeometry, antennaMaterial); antenna1.position.set(-1.5, 2, -3); antenna1.rotation.x = -0.3; detailGroup.add(antenna1); const antenna2 = new THREE.Mesh(antennaGeometry, antennaMaterial); antenna2.position.set(1.5, 2, -3); antenna2.rotation.x = -0.3; detailGroup.add(antenna2); // 导航灯 const navLightGeometry = new THREE.SphereGeometry(0.2, 16, 16); const redLightMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, emissive: 0xff5555 }); const greenLightMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00, emissive: 0x55ff55 }); const leftNavLight = new THREE.Mesh(navLightGeometry, redLightMaterial); leftNavLight.position.set(-3.8, 0, -5); detailGroup.add(leftNavLight); const rightNavLight = new THREE.Mesh(navLightGeometry, greenLightMaterial); rightNavLight.position.set(3.8, 0, -5); detailGroup.add(rightNavLight); group.add(detailGroup); group.position.y = -5; group.rotation.y = Math.PI; return group; } // 创建星空粒子 function createStarfield() { const starCount = 8000; const positions = new Float32Array(starCount * 3); const colors = new Float32Array(starCount * 3); const sizes = new Float32Array(starCount); for (let i = 0; i < starCount; i++) { const i3 = i * 3; // 随机位置 positions[i3] = (Math.random() - 0.5) * 2000; positions[i3 + 1] = (Math.random() - 0.5) * 2000; positions[i3 + 2] = (Math.random() - 0.5) * 2000; // 随机颜色(蓝白色调) const color = new THREE.Color( Math.random() * 0.5 + 0.5, Math.random() * 0.7 + 0.3, Math.random() * 0.8 + 0.2 ); colors[i3] = color.r; colors[i3 + 1] = color.g; colors[i3 + 2] = color.b; // 随机大小 sizes[i] = Math.random() * 1.5 + 0.5; } const geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3)); geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1)); const material = new THREE.PointsMaterial({ size: 2, vertexColors: true, transparent: true, opacity: 0.9, sizeAttenuation: true }); return new THREE.Points(geometry, material); } // 创建飞船轨迹粒子 function createTrail() { const trailCount = 200; const positions = new Float32Array(trailCount * 3); const colors = new Float32Array(trailCount * 3); for (let i = 0; i < trailCount; i++) { const i3 = i * 3; // 初始位置在飞船后面 positions[i3] = 0; positions[i3 + 1] = 0; positions[i3 + 2] = -i * 0.3; // 颜色从蓝色到青色渐变 colors[i3] = 0; colors[i3 + 1] = 0.5 + i * 0.002; colors[i3 + 2] = 1; } const geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3)); const material = new THREE.PointsMaterial({ size: 4, vertexColors: true, transparent: true, opacity: 0.8, sizeAttenuation: true, blending: THREE.AdditiveBlending }); return new THREE.Points(geometry, material); } // 创建飞船周围的能量场 function createEnergyField() { const geometry = new THREE.IcosahedronGeometry(6, 3); const material = new THREE.MeshBasicMaterial({ color: 0x00ffff, wireframe: true, transparent: true, opacity: 0.3 }); return new THREE.Mesh(geometry, material); } // 全局变量 let spaceship, stars, trail, energyField; // 加载资源并初始化场景 function initScene() { // 创建飞船 spaceship = createSpaceship(); scene.add(spaceship); // 创建星空 stars = createStarfield(); scene.add(stars); // 创建轨迹 - 作为飞船的子对象 trail = createTrail(); trail.position.set(0, 0, -5); // 定位到飞船尾部 spaceship.add(trail); // 创建能量场 - 作为飞船的子对象 energyField = createEnergyField(); spaceship.add(energyField); // 显示UI setTimeout(() => { document.querySelector('.overlay').style.opacity = 1; document.querySelector('.loading').style.display = 'none'; }, 1000); } // 动画循环 let time = 0; function animate() { requestAnimationFrame(animate); time += 0.01; // 飞船动画 if (spaceship) { spaceship.rotation.y = Math.sin(time * 0.5) * 0.1; spaceship.rotation.x = Math.sin(time * 0.3) * 0.05; spaceship.position.y = -5 + Math.sin(time) * 0.5; // 细节元素动画 const details = spaceship.getObjectByName("shipDetails"); if (details) { details.children.forEach((detail, index) => { if (detail.material && detail.material.emissive) { // 脉动发光效果 const intensity = 0.3 + Math
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值