ctx.fillStyle = astGrad; ctx.beginPath(); ctx.arc(ast.x, ast.y, size, 0, Math.PI * 2); ctx.fill(); // 选中效果 if (ast === selected) { ctx.strokeStyle = '#ffd700'; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(ast.x, ast.y, size + 2, 0, Math.PI * 2); ctx.stroke(); } }); // 粒子 particles.forEach(p => p.draw(ctx)); // 恢复状态 ctx.restore(); } // 大气层摧毁效果 function createAtmosphereDestruction(ast) { for (let i = 0; i < 30; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 3, (Math.random() - 0.5) * 3, 20 + Math.random() * 20, '#ff8c00' )); } notify(`大气层拦截: ${ast.name || '小行星'}`); } // 撞击效果 function createImpact(ast) { impactCount++; // 计算撞击能量(兆吨TNT当量) const energy = (0.5 * ast.diameter * ast.diameter * ast.diameter * 3000 * 12 * 12) / 4.184e15; // 计算陨石坑大小(千米) const craterSize = Math.pow(energy, 0.29) * 0.1; // 计算火球半径(千米) const fireballRadius = Math.pow(energy, 0.4) * 0.1; // 计算冲击波半径(千米) const shockwaveRadius = Math.pow(energy, 0.33) * 2; // 计算震级 const magnitude = Math.log10(energy * 4.184e15) / 1.5 - 4; // 创建陨石坑 craters.push({ x: ast.x, y: ast.y, r: Math.max(5, Math.log(ast.diameter) * 2), time: Date.now() }); // 创建爆炸粒子 for (let i = 0; i < 100; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 5, (Math.random() - 0.5) * 5, 30 + Math.random() * 30, i < 50 ? '#ff6b35' : '#ffd700' )); } // 更新撞击面板 document.getElementById('target').textContent = ast.name || '未知'; document.getElementById('energy').textContent = energy.toFixed(1) + ' MT'; document.getElementById('crater').textContent = craterSize.toFixed(1) + ' km'; document.getElementById('coords').textContent = `X:${Math.round(ast.x)} Y:${Math.round(ast.y)}`; document.getElementById('fireball').textContent = fireballRadius.toFixed(1) + ' km'; document.getElementById('shockwave').textContent = shockwaveRadius.toFixed(1) + ' km'; document.getElementById('magnitude').textContent = magnitude.toFixed(1); notify(`撞击发生! ${ast.name || '小行星'} - 能量: ${energy.toFixed(1)} MT`); } // 点击事件 function onClick(event) { const rect = canvas.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; // 查找点击的小行星 for (let i = asteroids.length - 1; i >= 0; i--) { const ast = asteroids[i]; const dist = Math.sqrt((x - ast.x) ** 2 + (y - ast.y) ** 2); if (dist <= ast.size + 5) { select(ast); return; } } // 如果没有点击到小行星,取消选择 selected = null; document.getElementById('impactBtn').disabled = true; updateList(); } // 选择小行星 function select(ast) { selected = ast; document.getElementById('impactBtn').disabled = false; updateList(); notify(`选择: ${ast.name || '小行星'}`); } // 更新小行星列表 function updateList() { const list = document.getElementById('list'); if (asteroids.length === 0) { list.innerHTML = '
暂无小行星
'; return; } list.innerHTML = asteroids.map(ast => `
${ast.name || '小行星'}
${ast.diameter}m | ${Math.sqrt(ast.vx * ast.vx + ast.vy * ast.vy).toFixed(1)}km/s
`).join(''); } // 添加小行星 function addAsteroid() { const angle = Math.random() * Math.PI * 2; const dist = 200 + Math.random() * 100; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 0.5 + Math.random() * 0.5; const ast = { id: Date.now(), name: `小行星-${asteroids.length + 1}`, diameter: 100 + Math.random() * 400, danger: Math.random() > 0.7, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`生成: ${ast.name}`); } // 添加目标小行星 function addTarget() { const ast = ASTEROIDS[Math.floor(Math.random() * ASTEROIDS.length)]; const angle = Math.random() * Math.PI * 2; const dist = 250; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 1.0; const newAst = { ...ast, id: Date.now(), x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; newAst.size = Math.max(3, Math.log(newAst.diameter) * 1.2); asteroids.push(newAst); updateList(); notify(`目标: ${newAst.name}`); } // 创建自定义小行星 function createCustom() { const size = parseInt(document.getElementById('size').value); const speedVal = parseInt(document.getElementById('speed').value); const angleVal = parseInt(document.getElementById('angle').value); const angle = angleVal * Math.PI / 180; const dist = 200; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = speedVal / 10; const ast = { id: Date.now(), name: `自定义-${size}m`, diameter: size, danger: size > 500, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`自定义: ${ast.name}`); } // 更新参数显示 function updateParams() { document.getElementById('sizeVal').textContent = document.getElementById('size').value + 'm'; document.getElementById('speedVal').textContent = document.getElementById('speed').value + 'km/s'; document.getElementById('angleVal').textContent = document.getElementById('angle').value + '°'; } // 撞击功能 function impact() { if (!selected) return; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const earthRadius = 45; // 计算撞击点(地球表面) const angle = Math.atan2(selected.y - centerY, selected.x - centerX); const impactX = centerX + Math.cos(angle) * earthRadius; const impactY = centerY + Math.sin(angle) * earthRadius; // 设置撞击模式 selected.impacting = true; selected.impactStartTime = Date.now(); selected.impactDuration = 2000; // 2秒撞击过程 selected.startX = selected.x; selected.startY = selected.y; selected.targetX = impactX; selected.targetY = impactY; document.getElementById('impactBtn').disabled = true; notify(`撞击模式启动: ${selected.name}`); } // 清除所有 function clearAll() { asteroids = []; particles = []; craters = []; selected = null; impactCount = 0; atmosphereDestroyCount = 0; updateList(); document.getElementById('impactBtn').disabled = true; notify('已清除所有小行星'); } // 清除小行星 function clear() { if (asteroids.length === 0) return; asteroids.pop(); if (selected && !asteroids.includes(selected)) { selected = null; document.getElementById('impactBtn').disabled = true; } updateList(); notify('清除一个小行星'); } // 更新UI function updateUI() { document.getElementById('count').textContent = asteroids.length; document.getElementById('impacts').textContent = impactCount; document.getElementById('atmosphere').textContent = atmosphereDestroyCount; document.getElementById('memory').textContent = memory.toFixed(1) + ' MB'; // 威胁等级 const threat = asteroids.filter(a => a.danger).length; document.getElementById('threat').textContent = threat > 3 ? '极高' : threat > 1 ? '高' : threat > 0 ? '中' : '低'; document.getElementById('threat').style.color = threat > 3 ? '#ff4757' : threat > 1 ? '#ffa502' : threat > 0 ? '#ffd700' : '#00ff88'; } // 更新NASA面板 function updateNASAPanel() { document.getElementById('neoCount').textContent = REAL_TIME_ASTEROIDS.length; document.getElementById('hazardCount').textContent = REAL_TIME_ASTEROIDS.filter(a => a.danger).length; document.getElementById('fireballCount').textContent = FIREBALL_DATA.length; document.getElementById('lastUpdate').textContent = new Date().toLocaleTimeString(); document.getElementById('dataSource').textContent = 'NASA NeoWs API'; } // 刷新NASA数据 function refreshNASAData() { initNASAData(); notify('刷新NASA数据...'); } // 切换所有面板显示 function toggleAllPanels() { const panels = document.querySelectorAll('.panel'); const viewControls = document.getElementById('viewControls'); const toggleBtn = document.getElementById('toggleBtn'); const allHidden = panels[0].classList.contains('hidden'); panels.forEach(panel => { if (allHidden) { panel.classList.remove('hidden'); } else { panel.classList.add('hidden'); } }); if (allHidden) { viewControls.classList.remove('hidden'); toggleBtn.textContent = '隐藏界面'; toggleBtn.classList.remove('all-hidden'); } else { viewControls.classList.add('hidden'); toggleBtn.textContent = '显示界面'; toggleBtn.classList.add('all-hidden'); } } // 设置视角 function setView(viewType, evt) { if (evt && evt.target) { // 更新按钮状态 document.querySelectorAll('.view-btn').forEach(btn => btn.classList.remove('active')); evt.target.classList.add('active'); } currentView = viewType; switch (viewType) { case 'default': viewScale = 1; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'close': viewScale = 2; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'wide': viewScale = 0.5; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'follow': if (selected) { followTarget = selected; viewScale = 1.5; } else { notify('请先选择一个小行星'); return; } break; } notify(`视角切换: ${getViewName(viewType)}`); } function getViewName(viewType) { const names = { 'default': '标准视角', 'close': '近距离', 'wide': '广角视角', 'follow': '跟踪模式' }; return names[viewType] || viewType; } // 暂停/继续 function togglePause() { isPaused = !isPaused; const pauseBtn = document.getElementById('pauseBtn'); pauseBtn.textContent = isPaused ? '继续' : '暂停'; notify(isPaused ? '模拟暂停' : '模拟继续'); } // 页面加载完成后初始化 window.addEventListener('load', init); // 窗口大小变化时调整canvas window.addEventListener('resize', () => { if (canvas) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } }); // 初始化参数显示 updateParams(); ctx.beginPath(); ctx.arc(ast.x, ast.y, size, 0, Math.PI * 2); ctx.fill(); // 选中效果 if (ast === selected) { ctx.strokeStyle = '#ffd700'; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(ast.x, ast.y, size + 2, 0, Math.PI * 2); ctx.stroke(); } }); // 粒子 particles.forEach(p => p.draw(ctx)); // 恢复状态 ctx.restore(); } // 大气层摧毁效果 function createAtmosphereDestruction(ast) { for (let i = 0; i < 30; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 3, (Math.random() - 0.5) * 3, 20 + Math.random() * 20, '#ff8c00' )); } notify(`大气层拦截: ${ast.name || '小行星'}`); } // 撞击效果 function createImpact(ast) { impactCount++; // 计算撞击能量(兆吨TNT当量) const energy = (0.5 * ast.diameter * ast.diameter * ast.diameter * 3000 * 12 * 12) / 4.184e15; // 计算陨石坑大小(千米) const craterSize = Math.pow(energy, 0.29) * 0.1; // 计算火球半径(千米) const fireballRadius = Math.pow(energy, 0.4) * 0.1; // 计算冲击波半径(千米) const shockwaveRadius = Math.pow(energy, 0.33) * 2; // 计算震级 const magnitude = Math.log10(energy * 4.184e15) / 1.5 - 4; // 创建陨石坑 craters.push({ x: ast.x, y: ast.y, r: Math.max(5, Math.log(ast.diameter) * 2), time: Date.now() }); // 创建爆炸粒子 for (let i = 0; i < 100; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 5, (Math.random() - 0.5) * 5, 30 + Math.random() * 30, i < 50 ? '#ff6b35' : '#ffd700' )); } // 更新撞击面板 document.getElementById('target').textContent = ast.name || '未知'; document.getElementById('energy').textContent = energy.toFixed(1) + ' MT'; document.getElementById('crater').textContent = craterSize.toFixed(1) + ' km'; document.getElementById('coords').textContent = `X:${Math.round(ast.x)} Y:${Math.round(ast.y)}`; document.getElementById('fireball').textContent = fireballRadius.toFixed(1) + ' km'; document.getElementById('shockwave').textContent = shockwaveRadius.toFixed(1) + ' km'; document.getElementById('magnitude').textContent = magnitude.toFixed(1); notify(`撞击发生! ${ast.name || '小行星'} - 能量: ${energy.toFixed(1)} MT`); } // 点击事件 function onClick(event) { const rect = canvas.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; // 查找点击的小行星 for (let i = asteroids.length - 1; i >= 0; i--) { const ast = asteroids[i]; const dist = Math.sqrt((x - ast.x) ** 2 + (y - ast.y) ** 2); if (dist <= ast.size + 5) { select(ast); return; } } // 如果没有点击到小行星,取消选择 selected = null; document.getElementById('impactBtn').disabled = true; updateList(); } // 选择小行星 function select(ast) { selected = ast; document.getElementById('impactBtn').disabled = false; updateList(); notify(`选择: ${ast.name || '小行星'}`); } // 更新小行星列表 function updateList() { const list = document.getElementById('list'); if (asteroids.length === 0) { list.innerHTML = '
暂无小行星
'; return; } list.innerHTML = asteroids.map(ast => `
${ast.name || '小行星'}
${ast.diameter}m | ${Math.sqrt(ast.vx * ast.vx + ast.vy * ast.vy).toFixed(1)}km/s
`).join(''); } // 添加小行星 function addAsteroid() { const angle = Math.random() * Math.PI * 2; const dist = 200 + Math.random() * 100; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 0.5 + Math.random() * 0.5; const ast = { id: Date.now(), name: `小行星-${asteroids.length + 1}`, diameter: 100 + Math.random() * 400, danger: Math.random() > 0.7, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`生成: ${ast.name}`); } // 添加目标小行星 function addTarget() { const ast = ASTEROIDS[Math.floor(Math.random() * ASTEROIDS.length)]; const angle = Math.random() * Math.PI * 2; const dist = 250; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 1.0; const newAst = { ...ast, id: Date.now(), x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; newAst.size = Math.max(3, Math.log(newAst.diameter) * 1.2); asteroids.push(newAst); updateList(); notify(`目标: ${newAst.name}`); } // 创建自定义小行星 function createCustom() { const size = parseInt(document.getElementById('size').value); const speedVal = parseInt(document.getElementById('speed').value); const angleVal = parseInt(document.getElementById('angle').value); const angle = angleVal * Math.PI / 180; const dist = 200; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = speedVal / 10; const ast = { id: Date.now(), name: `自定义-${size}m`, diameter: size, danger: size > 500, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`自定义: ${ast.name}`); } // 更新参数显示 function updateParams() { document.getElementById('sizeVal').textContent = document.getElementById('size').value + 'm'; document.getElementById('speedVal').textContent = document.getElementById('speed').value + 'km/s'; document.getElementById('angleVal').textContent = document.getElementById('angle').value + '°'; } // 撞击功能 function impact() { if (!selected) return; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const earthRadius = 45; // 计算撞击点(地球表面) const angle = Math.atan2(selected.y - centerY, selected.x - centerX); const impactX = centerX + Math.cos(angle) * earthRadius; const impactY = centerY + Math.sin(angle) * earthRadius; // 设置撞击模式 selected.impacting = true; selected.impactStartTime = Date.now(); selected.impactDuration = 2000; // 2秒撞击过程 selected.startX = selected.x; selected.startY = selected.y; selected.targetX = impactX; selected.targetY = impactY; document.getElementById('impactBtn').disabled = true; notify(`撞击模式启动: ${selected.name}`); } // 清除所有 function clearAll() { asteroids = []; particles = []; craters = []; selected = null; impactCount = 0; atmosphereDestroyCount = 0; updateList(); document.getElementById('impactBtn').disabled = true; notify('已清除所有小行星'); } // 清除小行星 function clear() { if (asteroids.length === 0) return; asteroids.pop(); if (selected && !asteroids.includes(selected)) { selected = null; document.getElementById('impactBtn').disabled = true; } updateList(); notify('清除一个小行星'); } // 更新UI function updateUI() { document.getElementById('count').textContent = asteroids.length; document.getElementById('impacts').textContent = impactCount; document.getElementById('atmosphere').textContent = atmosphereDestroyCount; document.getElementById('memory').textContent = memory.toFixed(1) + ' MB'; // 威胁等级 const threat = asteroids.filter(a => a.danger).length; document.getElementById('threat').textContent = threat > 3 ? '极高' : threat > 1 ? '高' : threat > 0 ? '中' : '低'; document.getElementById('threat').style.color = threat > 3 ? '#ff4757' : threat > 1 ? '#ffa502' : threat > 0 ? '#ffd700' : '#00ff88'; } // 更新NASA面板 function updateNASAPanel() { document.getElementById('neoCount').textContent = REAL_TIME_ASTEROIDS.length; document.getElementById('hazardCount').textContent = REAL_TIME_ASTEROIDS.filter(a => a.danger).length; document.getElementById('fireballCount').textContent = FIREBALL_DATA.length; document.getElementById('lastUpdate').textContent = new Date().toLocaleTimeString(); document.getElementById('dataSource').textContent = 'NASA NeoWs API'; } // 刷新NASA数据 function refreshNASAData() { initNASAData(); notify('刷新NASA数据...'); } // 切换所有面板显示 function toggleAllPanels() { const panels = document.querySelectorAll('.panel'); const viewControls = document.getElementById('viewControls'); const toggleBtn = document.getElementById('toggleBtn'); const allHidden = panels[0].classList.contains('hidden'); panels.forEach(panel => { if (allHidden) { panel.classList.remove('hidden'); } else { panel.classList.add('hidden'); } }); if (allHidden) { viewControls.classList.remove('hidden'); toggleBtn.textContent = '隐藏界面'; toggleBtn.classList.remove('all-hidden'); } else { viewControls.classList.add('hidden'); toggleBtn.textContent = '显示界面'; toggleBtn.classList.add('all-hidden'); } } // 设置视角 function setView(viewType, evt) { if (evt && evt.target) { // 更新按钮状态 document.querySelectorAll('.view-btn').forEach(btn => btn.classList.remove('active')); evt.target.classList.add('active'); } currentView = viewType; switch (viewType) { case 'default': viewScale = 1; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'close': viewScale = 2; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'wide': viewScale = 0.5; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'follow': if (selected) { followTarget = selected; viewScale = 1.5; } else { notify('请先选择一个小行星'); return; } break; } notify(`视角切换: ${getViewName(viewType)}`); } function getViewName(viewType) { const names = { 'default': '标准视角', 'close': '近距离', 'wide': '广角视角', 'follow': '跟踪模式' }; return names[viewType] || viewType; } // 暂停/继续 function togglePause() { isPaused = !isPaused; const pauseBtn = document.getElementById('pauseBtn'); pauseBtn.textContent = isPaused ? '继续' : '暂停'; notify(isPaused ? '模拟暂停' : '模拟继续'); } // 页面加载完成后初始化 window.addEventListener('load', init); // 窗口大小变化时调整canvas window.addEventListener('resize', () => { if (canvas) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } }); // 初始化参数显示 updateParams(); ctx.beginPath(); ctx.arc(ast.x, ast.y, size, 0, Math.PI * 2); ctx.fill(); // 选中效果 if (ast === selected) { ctx.strokeStyle = '#ffd700'; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(ast.x, ast.y, size + 2, 0, Math.PI * 2); ctx.stroke(); } }); // 粒子 particles.forEach(p => p.draw(ctx)); // 恢复状态 ctx.restore(); } // 大气层摧毁效果 function createAtmosphereDestruction(ast) { for (let i = 0; i < 30; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 3, (Math.random() - 0.5) * 3, 20 + Math.random() * 20, '#ff8c00' )); } notify(`大气层拦截: ${ast.name || '小行星'}`); } // 撞击效果 function createImpact(ast) { impactCount++; // 计算撞击能量(兆吨TNT当量) const energy = (0.5 * ast.diameter * ast.diameter * ast.diameter * 3000 * 12 * 12) / 4.184e15; // 计算陨石坑大小(千米) const craterSize = Math.pow(energy, 0.29) * 0.1; // 计算火球半径(千米) const fireballRadius = Math.pow(energy, 0.4) * 0.1; // 计算冲击波半径(千米) const shockwaveRadius = Math.pow(energy, 0.33) * 2; // 计算震级 const magnitude = Math.log10(energy * 4.184e15) / 1.5 - 4; // 创建陨石坑 craters.push({ x: ast.x, y: ast.y, r: Math.max(5, Math.log(ast.diameter) * 2), time: Date.now() }); // 创建爆炸粒子 for (let i = 0; i < 100; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 5, (Math.random() - 0.5) * 5, 30 + Math.random() * 30, i < 50 ? '#ff6b35' : '#ffd700' )); } // 更新撞击面板 document.getElementById('target').textContent = ast.name || '未知'; document.getElementById('energy').textContent = energy.toFixed(1) + ' MT'; document.getElementById('crater').textContent = craterSize.toFixed(1) + ' km'; document.getElementById('coords').textContent = `X:${Math.round(ast.x)} Y:${Math.round(ast.y)}`; document.getElementById('fireball').textContent = fireballRadius.toFixed(1) + ' km'; document.getElementById('shockwave').textContent = shockwaveRadius.toFixed(1) + ' km'; document.getElementById('magnitude').textContent = magnitude.toFixed(1); notify(`撞击发生! ${ast.name || '小行星'} - 能量: ${energy.toFixed(1)} MT`); } // 点击事件 function onClick(event) { const rect = canvas.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; // 查找点击的小行星 for (let i = asteroids.length - 1; i >= 0; i--) { const ast = asteroids[i]; const dist = Math.sqrt((x - ast.x) ** 2 + (y - ast.y) ** 2); if (dist <= ast.size + 5) { select(ast); return; } } // 如果没有点击到小行星,取消选择 selected = null; document.getElementById('impactBtn').disabled = true; updateList(); } // 选择小行星 function select(ast) { selected = ast; document.getElementById('impactBtn').disabled = false; updateList(); notify(`选择: ${ast.name || '小行星'}`); } // 更新小行星列表 function updateList() { const list = document.getElementById('list'); if (asteroids.length === 0) { list.innerHTML = '
暂无小行星
'; return; } list.innerHTML = asteroids.map(ast => `
${ast.name || '小行星'}
${ast.diameter}m | ${Math.sqrt(ast.vx * ast.vx + ast.vy * ast.vy).toFixed(1)}km/s
`).join(''); } // 添加小行星 function addAsteroid() { const angle = Math.random() * Math.PI * 2; const dist = 200 + Math.random() * 100; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 0.5 + Math.random() * 0.5; const ast = { id: Date.now(), name: `小行星-${asteroids.length + 1}`, diameter: 100 + Math.random() * 400, danger: Math.random() > 0.7, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`生成: ${ast.name}`); } // 添加目标小行星 function addTarget() { const ast = ASTEROIDS[Math.floor(Math.random() * ASTEROIDS.length)]; const angle = Math.random() * Math.PI * 2; const dist = 250; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 1.0; const newAst = { ...ast, id: Date.now(), x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; newAst.size = Math.max(3, Math.log(newAst.diameter) * 1.2); asteroids.push(newAst); updateList(); notify(`目标: ${newAst.name}`); } // 创建自定义小行星 function createCustom() { const size = parseInt(document.getElementById('size').value); const speedVal = parseInt(document.getElementById('speed').value); const angleVal = parseInt(document.getElementById('angle').value); const angle = angleVal * Math.PI / 180; const dist = 200; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = speedVal / 10; const ast = { id: Date.now(), name: `自定义-${size}m`, diameter: size, danger: size > 500, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`自定义: ${ast.name}`); } // 更新参数显示 function updateParams() { document.getElementById('sizeVal').textContent = document.getElementById('size').value + 'm'; document.getElementById('speedVal').textContent = document.getElementById('speed').value + 'km/s'; document.getElementById('angleVal').textContent = document.getElementById('angle').value + '°'; } // 撞击功能 function impact() { if (!selected) return; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const earthRadius = 45; // 计算撞击点(地球表面) const angle = Math.atan2(selected.y - centerY, selected.x - centerX); const impactX = centerX + Math.cos(angle) * earthRadius; const impactY = centerY + Math.sin(angle) * earthRadius; // 设置撞击模式 selected.impacting = true; selected.impactStartTime = Date.now(); selected.impactDuration = 2000; // 2秒撞击过程 selected.startX = selected.x; selected.startY = selected.y; selected.targetX = impactX; selected.targetY = impactY; document.getElementById('impactBtn').disabled = true; notify(`撞击模式启动: ${selected.name}`); } // 清除所有 function clearAll() { asteroids = []; particles = []; craters = []; selected = null; impactCount = 0; atmosphereDestroyCount = 0; updateList(); document.getElementById('impactBtn').disabled = true; notify('已清除所有小行星'); } // 清除小行星 function clear() { if (asteroids.length === 0) return; asteroids.pop(); if (selected && !asteroids.includes(selected)) { selected = null; document.getElementById('impactBtn').disabled = true; } updateList(); notify('清除一个小行星'); } // 更新UI function updateUI() { document.getElementById('count').textContent = asteroids.length; document.getElementById('impacts').textContent = impactCount; document.getElementById('atmosphere').textContent = atmosphereDestroyCount; document.getElementById('memory').textContent = memory.toFixed(1) + ' MB'; // 威胁等级 const threat = asteroids.filter(a => a.danger).length; document.getElementById('threat').textContent = threat > 3 ? '极高' : threat > 1 ? '高' : threat > 0 ? '中' : '低'; document.getElementById('threat').style.color = threat > 3 ? '#ff4757' : threat > 1 ? '#ffa502' : threat > 0 ? '#ffd700' : '#00ff88'; } // 更新NASA面板 function updateNASAPanel() { document.getElementById('neoCount').textContent = REAL_TIME_ASTEROIDS.length; document.getElementById('hazardCount').textContent = REAL_TIME_ASTEROIDS.filter(a => a.danger).length; document.getElementById('fireballCount').textContent = FIREBALL_DATA.length; document.getElementById('lastUpdate').textContent = new Date().toLocaleTimeString(); document.getElementById('dataSource').textContent = 'NASA NeoWs API'; } // 刷新NASA数据 function refreshNASAData() { initNASAData(); notify('刷新NASA数据...'); } // 切换所有面板显示 function toggleAllPanels() { const panels = document.querySelectorAll('.panel'); const viewControls = document.getElementById('viewControls'); const toggleBtn = document.getElementById('toggleBtn'); const allHidden = panels[0].classList.contains('hidden'); panels.forEach(panel => { if (allHidden) { panel.classList.remove('hidden'); } else { panel.classList.add('hidden'); } }); if (allHidden) { viewControls.classList.remove('hidden'); toggleBtn.textContent = '隐藏界面'; toggleBtn.classList.remove('all-hidden'); } else { viewControls.classList.add('hidden'); toggleBtn.textContent = '显示界面'; toggleBtn.classList.add('all-hidden'); } } // 设置视角 function setView(viewType, evt) { if (evt && evt.target) { // 更新按钮状态 document.querySelectorAll('.view-btn').forEach(btn => btn.classList.remove('active')); evt.target.classList.add('active'); } currentView = viewType; switch (viewType) { case 'default': viewScale = 1; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'close': viewScale = 2; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'wide': viewScale = 0.5; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'follow': if (selected) { followTarget = selected; viewScale = 1.5; } else { notify('请先选择一个小行星'); return; } break; } notify(`视角切换: ${getViewName(viewType)}`); } function getViewName(viewType) { const names = { 'default': '标准视角', 'close': '近距离', 'wide': '广角视角', 'follow': '跟踪模式' }; return names[viewType] || viewType; } // 暂停/继续 function togglePause() { isPaused = !isPaused; const pauseBtn = document.getElementById('pauseBtn'); pauseBtn.textContent = isPaused ? '继续' : '暂停'; notify(isPaused ? '模拟暂停' : '模拟继续'); } // 页面加载完成后初始化 window.addEventListener('load', init); // 窗口大小变化时调整canvas window.addEventListener('resize', () => { if (canvas) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } }); // 初始化参数显示 updateParams(); ctx.beginPath(); ctx.arc(ast.x, ast.y, size, 0, Math.PI * 2); ctx.fill(); // 选中效果 if (ast === selected) { ctx.strokeStyle = '#ffd700'; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(ast.x, ast.y, size + 2, 0, Math.PI * 2); ctx.stroke(); } }); // 粒子 particles.forEach(p => p.draw(ctx)); // 恢复状态 ctx.restore(); } // 大气层摧毁效果 function createAtmosphereDestruction(ast) { for (let i = 0; i < 30; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 3, (Math.random() - 0.5) * 3, 20 + Math.random() * 20, '#ff8c00' )); } notify(`大气层拦截: ${ast.name || '小行星'}`); } // 撞击效果 function createImpact(ast) { impactCount++; // 计算撞击能量(兆吨TNT当量) const energy = (0.5 * ast.diameter * ast.diameter * ast.diameter * 3000 * 12 * 12) / 4.184e15; // 计算陨石坑大小(千米) const craterSize = Math.pow(energy, 0.29) * 0.1; // 计算火球半径(千米) const fireballRadius = Math.pow(energy, 0.4) * 0.1; // 计算冲击波半径(千米) const shockwaveRadius = Math.pow(energy, 0.33) * 2; // 计算震级 const magnitude = Math.log10(energy * 4.184e15) / 1.5 - 4; // 创建陨石坑 craters.push({ x: ast.x, y: ast.y, r: Math.max(5, Math.log(ast.diameter) * 2), time: Date.now() }); // 创建爆炸粒子 for (let i = 0; i < 100; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 5, (Math.random() - 0.5) * 5, 30 + Math.random() * 30, i < 50 ? '#ff6b35' : '#ffd700' )); } // 更新撞击面板 document.getElementById('target').textContent = ast.name || '未知'; document.getElementById('energy').textContent = energy.toFixed(1) + ' MT'; document.getElementById('crater').textContent = craterSize.toFixed(1) + ' km'; document.getElementById('coords').textContent = `X:${Math.round(ast.x)} Y:${Math.round(ast.y)}`; document.getElementById('fireball').textContent = fireballRadius.toFixed(1) + ' km'; document.getElementById('shockwave').textContent = shockwaveRadius.toFixed(1) + ' km'; document.getElementById('magnitude').textContent = magnitude.toFixed(1); notify(`撞击发生! ${ast.name || '小行星'} - 能量: ${energy.toFixed(1)} MT`); } // 点击事件 function onClick(event) { const rect = canvas.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; // 查找点击的小行星 for (let i = asteroids.length - 1; i >= 0; i--) { const ast = asteroids[i]; const dist = Math.sqrt((x - ast.x) ** 2 + (y - ast.y) ** 2); if (dist <= ast.size + 5) { select(ast); return; } } // 如果没有点击到小行星,取消选择 selected = null; document.getElementById('impactBtn').disabled = true; updateList(); } // 选择小行星 function select(ast) { selected = ast; document.getElementById('impactBtn').disabled = false; updateList(); notify(`选择: ${ast.name || '小行星'}`); } // 更新小行星列表 function updateList() { const list = document.getElementById('list'); if (asteroids.length === 0) { list.innerHTML = '
暂无小行星
'; return; } list.innerHTML = asteroids.map(ast => `
${ast.name || '小行星'}
${ast.diameter}m | ${Math.sqrt(ast.vx * ast.vx + ast.vy * ast.vy).toFixed(1)}km/s
`).join(''); } // 添加小行星 function addAsteroid() { const angle = Math.random() * Math.PI * 2; const dist = 200 + Math.random() * 100; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 0.5 + Math.random() * 0.5; const ast = { id: Date.now(), name: `小行星-${asteroids.length + 1}`, diameter: 100 + Math.random() * 400, danger: Math.random() > 0.7, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`生成: ${ast.name}`); } // 添加目标小行星 function addTarget() { const ast = ASTEROIDS[Math.floor(Math.random() * ASTEROIDS.length)]; const angle = Math.random() * Math.PI * 2; const dist = 250; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 1.0; const newAst = { ...ast, id: Date.now(), x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; newAst.size = Math.max(3, Math.log(newAst.diameter) * 1.2); asteroids.push(newAst); updateList(); notify(`目标: ${newAst.name}`); } // 创建自定义小行星 function createCustom() { const size = parseInt(document.getElementById('size').value); const speedVal = parseInt(document.getElementById('speed').value); const angleVal = parseInt(document.getElementById('angle').value); const angle = angleVal * Math.PI / 180; const dist = 200; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = speedVal / 10; const ast = { id: Date.now(), name: `自定义-${size}m`, diameter: size, danger: size > 500, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`自定义: ${ast.name}`); } // 更新参数显示 function updateParams() { document.getElementById('sizeVal').textContent = document.getElementById('size').value + 'm'; document.getElementById('speedVal').textContent = document.getElementById('speed').value + 'km/s'; document.getElementById('angleVal').textContent = document.getElementById('angle').value + '°'; } // 撞击功能 function impact() { if (!selected) return; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const earthRadius = 45; // 计算撞击点(地球表面) const angle = Math.atan2(selected.y - centerY, selected.x - centerX); const impactX = centerX + Math.cos(angle) * earthRadius; const impactY = centerY + Math.sin(angle) * earthRadius; // 设置撞击模式 selected.impacting = true; selected.impactStartTime = Date.now(); selected.impactDuration = 2000; // 2秒撞击过程 selected.startX = selected.x; selected.startY = selected.y; selected.targetX = impactX; selected.targetY = impactY; document.getElementById('impactBtn').disabled = true; notify(`撞击模式启动: ${selected.name}`); } // 清除所有 function clearAll() { asteroids = []; particles = []; craters = []; selected = null; impactCount = 0; atmosphereDestroyCount = 0; updateList(); document.getElementById('impactBtn').disabled = true; notify('已清除所有小行星'); } // 清除小行星 function clear() { if (asteroids.length === 0) return; asteroids.pop(); if (selected && !asteroids.includes(selected)) { selected = null; document.getElementById('impactBtn').disabled = true; } updateList(); notify('清除一个小行星'); } // 更新UI function updateUI() { document.getElementById('count').textContent = asteroids.length; document.getElementById('impacts').textContent = impactCount; document.getElementById('atmosphere').textContent = atmosphereDestroyCount; document.getElementById('memory').textContent = memory.toFixed(1) + ' MB'; // 威胁等级 const threat = asteroids.filter(a => a.danger).length; document.getElementById('threat').textContent = threat > 3 ? '极高' : threat > 1 ? '高' : threat > 0 ? '中' : '低'; document.getElementById('threat').style.color = threat > 3 ? '#ff4757' : threat > 1 ? '#ffa502' : threat > 0 ? '#ffd700' : '#00ff88'; } // 更新NASA面板 function updateNASAPanel() { document.getElementById('neoCount').textContent = REAL_TIME_ASTEROIDS.length; document.getElementById('hazardCount').textContent = REAL_TIME_ASTEROIDS.filter(a => a.danger).length; document.getElementById('fireballCount').textContent = FIREBALL_DATA.length; document.getElementById('lastUpdate').textContent = new Date().toLocaleTimeString(); document.getElementById('dataSource').textContent = 'NASA NeoWs API'; } // 刷新NASA数据 function refreshNASAData() { initNASAData(); notify('刷新NASA数据...'); } // 切换所有面板显示 function toggleAllPanels() { const panels = document.querySelectorAll('.panel'); const viewControls = document.getElementById('viewControls'); const toggleBtn = document.getElementById('toggleBtn'); const allHidden = panels[0].classList.contains('hidden'); panels.forEach(panel => { if (allHidden) { panel.classList.remove('hidden'); } else { panel.classList.add('hidden'); } }); if (allHidden) { viewControls.classList.remove('hidden'); toggleBtn.textContent = '隐藏界面'; toggleBtn.classList.remove('all-hidden'); } else { viewControls.classList.add('hidden'); toggleBtn.textContent = '显示界面'; toggleBtn.classList.add('all-hidden'); } } // 设置视角 function setView(viewType, evt) { if (evt && evt.target) { // 更新按钮状态 document.querySelectorAll('.view-btn').forEach(btn => btn.classList.remove('active')); evt.target.classList.add('active'); } currentView = viewType; switch (viewType) { case 'default': viewScale = 1; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'close': viewScale = 2; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'wide': viewScale = 0.5; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'follow': if (selected) { followTarget = selected; viewScale = 1.5; } else { notify('请先选择一个小行星'); return; } break; } notify(`视角切换: ${getViewName(viewType)}`); } function getViewName(viewType) { const names = { 'default': '标准视角', 'close': '近距离', 'wide': '广角视角', 'follow': '跟踪模式' }; return names[viewType] || viewType; } // 暂停/继续 function togglePause() { isPaused = !isPaused; const pauseBtn = document.getElementById('pauseBtn'); pauseBtn.textContent = isPaused ? '继续' : '暂停'; notify(isPaused ? '模拟暂停' : '模拟继续'); } // 页面加载完成后初始化 window.addEventListener('load', init); // 窗口大小变化时调整canvas window.addEventListener('resize', () => { if (canvas) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } }); // 初始化参数显示 updateParams(); ctx.beginPath(); ctx.arc(ast.x, ast.y, size, 0, Math.PI * 2); ctx.fill(); // 选中效果 if (ast === selected) { ctx.strokeStyle = '#ffd700'; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(ast.x, ast.y, size + 2, 0, Math.PI * 2); ctx.stroke(); } }); // 粒子 particles.forEach(p => p.draw(ctx)); // 恢复状态 ctx.restore(); } // 大气层摧毁效果 function createAtmosphereDestruction(ast) { for (let i = 0; i < 30; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 3, (Math.random() - 0.5) * 3, 20 + Math.random() * 20, '#ff8c00' )); } notify(`大气层拦截: ${ast.name || '小行星'}`); } // 撞击效果 function createImpact(ast) { impactCount++; // 计算撞击能量(兆吨TNT当量) const energy = (0.5 * ast.diameter * ast.diameter * ast.diameter * 3000 * 12 * 12) / 4.184e15; // 计算陨石坑大小(千米) const craterSize = Math.pow(energy, 0.29) * 0.1; // 计算火球半径(千米) const fireballRadius = Math.pow(energy, 0.4) * 0.1; // 计算冲击波半径(千米) const shockwaveRadius = Math.pow(energy, 0.33) * 2; // 计算震级 const magnitude = Math.log10(energy * 4.184e15) / 1.5 - 4; // 创建陨石坑 craters.push({ x: ast.x, y: ast.y, r: Math.max(5, Math.log(ast.diameter) * 2), time: Date.now() }); // 创建爆炸粒子 for (let i = 0; i < 100; i++) { particles.push(new Particle( ast.x, ast.y, (Math.random() - 0.5) * 5, (Math.random() - 0.5) * 5, 30 + Math.random() * 30, i < 50 ? '#ff6b35' : '#ffd700' )); } // 更新撞击面板 document.getElementById('target').textContent = ast.name || '未知'; document.getElementById('energy').textContent = energy.toFixed(1) + ' MT'; document.getElementById('crater').textContent = craterSize.toFixed(1) + ' km'; document.getElementById('coords').textContent = `X:${Math.round(ast.x)} Y:${Math.round(ast.y)}`; document.getElementById('fireball').textContent = fireballRadius.toFixed(1) + ' km'; document.getElementById('shockwave').textContent = shockwaveRadius.toFixed(1) + ' km'; document.getElementById('magnitude').textContent = magnitude.toFixed(1); notify(`撞击发生! ${ast.name || '小行星'} - 能量: ${energy.toFixed(1)} MT`); } // 点击事件 function onClick(event) { const rect = canvas.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; // 查找点击的小行星 for (let i = asteroids.length - 1; i >= 0; i--) { const ast = asteroids[i]; const dist = Math.sqrt((x - ast.x) ** 2 + (y - ast.y) ** 2); if (dist <= ast.size + 5) { select(ast); return; } } // 如果没有点击到小行星,取消选择 selected = null; document.getElementById('impactBtn').disabled = true; updateList(); } // 选择小行星 function select(ast) { selected = ast; document.getElementById('impactBtn').disabled = false; updateList(); notify(`选择: ${ast.name || '小行星'}`); } // 更新小行星列表 function updateList() { const list = document.getElementById('list'); if (asteroids.length === 0) { list.innerHTML = '
暂无小行星
'; return; } list.innerHTML = asteroids.map(ast => `
${ast.name || '小行星'}
${ast.diameter}m | ${Math.sqrt(ast.vx * ast.vx + ast.vy * ast.vy).toFixed(1)}km/s
`).join(''); } // 添加小行星 function addAsteroid() { const angle = Math.random() * Math.PI * 2; const dist = 200 + Math.random() * 100; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 0.5 + Math.random() * 0.5; const ast = { id: Date.now(), name: `小行星-${asteroids.length + 1}`, diameter: 100 + Math.random() * 400, danger: Math.random() > 0.7, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`生成: ${ast.name}`); } // 添加目标小行星 function addTarget() { const ast = ASTEROIDS[Math.floor(Math.random() * ASTEROIDS.length)]; const angle = Math.random() * Math.PI * 2; const dist = 250; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = 1.0; const newAst = { ...ast, id: Date.now(), x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; newAst.size = Math.max(3, Math.log(newAst.diameter) * 1.2); asteroids.push(newAst); updateList(); notify(`目标: ${newAst.name}`); } // 创建自定义小行星 function createCustom() { const size = parseInt(document.getElementById('size').value); const speedVal = parseInt(document.getElementById('speed').value); const angleVal = parseInt(document.getElementById('angle').value); const angle = angleVal * Math.PI / 180; const dist = 200; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const startX = centerX + Math.cos(angle) * dist; const startY = centerY + Math.sin(angle) * dist; const dirX = centerX - startX; const dirY = centerY - startY; const len = Math.sqrt(dirX * dirX + dirY * dirY); const speed = speedVal / 10; const ast = { id: Date.now(), name: `自定义-${size}m`, diameter: size, danger: size > 500, x: startX, y: startY, vx: (dirX / len) * speed, vy: (dirY / len) * speed }; ast.size = Math.max(3, Math.log(ast.diameter) * 1.2); asteroids.push(ast); updateList(); notify(`自定义: ${ast.name}`); } // 更新参数显示 function updateParams() { document.getElementById('sizeVal').textContent = document.getElementById('size').value + 'm'; document.getElementById('speedVal').textContent = document.getElementById('speed').value + 'km/s'; document.getElementById('angleVal').textContent = document.getElementById('angle').value + '°'; } // 撞击功能 function impact() { if (!selected) return; const centerX = canvas.width / 2; const centerY = canvas.height / 2; const earthRadius = 45; // 计算撞击点(地球表面) const angle = Math.atan2(selected.y - centerY, selected.x - centerX); const impactX = centerX + Math.cos(angle) * earthRadius; const impactY = centerY + Math.sin(angle) * earthRadius; // 设置撞击模式 selected.impacting = true; selected.impactStartTime = Date.now(); selected.impactDuration = 2000; // 2秒撞击过程 selected.startX = selected.x; selected.startY = selected.y; selected.targetX = impactX; selected.targetY = impactY; document.getElementById('impactBtn').disabled = true; notify(`撞击模式启动: ${selected.name}`); } // 清除所有 function clearAll() { asteroids = []; particles = []; craters = []; selected = null; impactCount = 0; atmosphereDestroyCount = 0; updateList(); document.getElementById('impactBtn').disabled = true; notify('已清除所有小行星'); } // 清除小行星 function clear() { if (asteroids.length === 0) return; asteroids.pop(); if (selected && !asteroids.includes(selected)) { selected = null; document.getElementById('impactBtn').disabled = true; } updateList(); notify('清除一个小行星'); } // 更新UI function updateUI() { document.getElementById('count').textContent = asteroids.length; document.getElementById('impacts').textContent = impactCount; document.getElementById('atmosphere').textContent = atmosphereDestroyCount; document.getElementById('memory').textContent = memory.toFixed(1) + ' MB'; // 威胁等级 const threat = asteroids.filter(a => a.danger).length; document.getElementById('threat').textContent = threat > 3 ? '极高' : threat > 1 ? '高' : threat > 0 ? '中' : '低'; document.getElementById('threat').style.color = threat > 3 ? '#ff4757' : threat > 1 ? '#ffa502' : threat > 0 ? '#ffd700' : '#00ff88'; } // 更新NASA面板 function updateNASAPanel() { document.getElementById('neoCount').textContent = REAL_TIME_ASTEROIDS.length; document.getElementById('hazardCount').textContent = REAL_TIME_ASTEROIDS.filter(a => a.danger).length; document.getElementById('fireballCount').textContent = FIREBALL_DATA.length; document.getElementById('lastUpdate').textContent = new Date().toLocaleTimeString(); document.getElementById('dataSource').textContent = 'NASA NeoWs API'; } // 刷新NASA数据 function refreshNASAData() { initNASAData(); notify('刷新NASA数据...'); } // 切换所有面板显示 function toggleAllPanels() { const panels = document.querySelectorAll('.panel'); const viewControls = document.getElementById('viewControls'); const toggleBtn = document.getElementById('toggleBtn'); const allHidden = panels[0].classList.contains('hidden'); panels.forEach(panel => { if (allHidden) { panel.classList.remove('hidden'); } else { panel.classList.add('hidden'); } }); if (allHidden) { viewControls.classList.remove('hidden'); toggleBtn.textContent = '隐藏界面'; toggleBtn.classList.remove('all-hidden'); } else { viewControls.classList.add('hidden'); toggleBtn.textContent = '显示界面'; toggleBtn.classList.add('all-hidden'); } } // 设置视角 function setView(viewType, evt) { if (evt && evt.target) { // 更新按钮状态 document.querySelectorAll('.view-btn').forEach(btn => btn.classList.remove('active')); evt.target.classList.add('active'); } currentView = viewType; switch (viewType) { case 'default': viewScale = 1; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'close': viewScale = 2; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'wide': viewScale = 0.5; viewOffsetX = 0; viewOffsetY = 0; followTarget = null; break; case 'follow': if (selected) { followTarget = selected; viewScale = 1.5; } else { notify('请先选择一个小行星'); return; } break; } notify(`视角切换: ${getViewName(viewType)}`); } function getViewName(viewType) { const names = { 'default': '标准视角', 'close': '近距离', 'wide': '广角视角', 'follow': '跟踪模式' }; return names[viewType] || viewType; } // 暂停/继续 function togglePause() { isPaused = !isPaused; const pauseBtn = document.getElementById('pauseBtn'); pauseBtn.textContent = isPaused ? '继续' : '暂停'; notify(isPaused ? '模拟暂停' : '模拟继续'); } // 页面加载完成后初始化 window.addEventListener('load', init); // 窗口大小变化时调整canvas window.addEventListener('resize', () => { if (canvas) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } }); // 初始化参数显示 updateParams(); 小行星撞击模拟器

地球防御

小行星:0
撞击:0
大气拦截:0
威胁:
内存:10.5 MB
FPS:60

控制

暂无小行星

参数

500m
12km/s
45°

撞击数据

目标:
能量:0 MT
陨石坑:0 km
坐标:N/A
火球半径:0 km
冲击波:0 km
震级:0.0

NASA小行星列表

加载中...

NASA实时数据

数据源:加载中...
近地天体:0
危险天体:0
火球事件:0
更新:-