问题标题: 1111

1
0
已解决
陆梓骞
陆梓骞
新手守护
新手守护

file:///C:/Users/lx/Desktop/%E6%81%92%E6%98%9F%E6%A8%A1%E6%8B%9F%E5%99%A8v11.html

陆梓骞在2026-07-10 08:59:51追加了内容
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>引力模拟器 自定义直径+颜色弹窗版</title>
<**>
*{margin:0;padding:0;overflow:hidden;background:#000;}
canvas{display:block;}
.info{position:fixed;top:15px;left:15px;color:#fff;font-size:16px;font-family:微软雅黑;z-index:99;}
/* 自定义弹窗样式 */
.modalMask{
    position:fixed;top:0;left:0;width:100vw;height:100vh;
    background:rgba(0,0,0,0.7);z-index:9999;display:flex;
    align-items:center;justify-content:center;
}
.modalBox{
    background:#1a1a2e;padding:24px;border-radius:10px;
    min-width:320px;color:#fff;font-family:微软雅黑;
}
.modalBox h3{margin:0 0 16px 0;text-align:center;}
.row{margin:12px 0;display:flex;align-items:center;gap:10px;}
.row label{width:90px;}
.row input{padding:6px;width:180px;font-size:14px;}
.btnWrap{margin-top:20px;display:flex;gap:12px;justify-content:center;}
.btn{padding:7px 22px;border:none;border-radius:6px;cursor:pointer;font-size:14px;}
.btnOk{background:#2196F3;color:#fff;}
.btnCancel{background:#666;color:#fff;}
</**>
</head>
<body>
<div class="info">左键空白=恒星(弹窗设置直径+颜色)|右键空白=黑洞(弹窗设置直径)|左键点天体选中|R开启/关闭遥控|方向键仅操控选中天体|Z加速 X减速|C清空</div>
<canvas id="c"></canvas>

<**>
const canvas = **.getElementById('c');
const ctx = canvas.getContext('2d');
canvas.width = innerWidth;
canvas.height = innerHeight;

const G = 120;
let speed = 1;
let stars = [];
let blackHoles = [];
let selectedTarget = null;
let isControlMode = false;
const controlForce = 0.8;
const keyState = {};

// 自定义弹窗函数:返回 {diameter,color} 或 null(取消)
function openCreateModal(isStar,defaultD,defaultColor){
    return new Promise(resolve=>{
        // 遮罩层
        const mask = **.createElement('div');
        mask.className = 'modalMask';
        // 弹窗内容
        let colorHtml = '';
        if(isStar){
            colorHtml = `
            <div class="row">
                <label>天体颜色</label>
                <input type="color" id="colorInp" value="${defaultColor}">
            </div>`;
        }
        mask.innerHTML = `
        <div class="modalBox">
            <h3>${isStar ? "创建恒星" : "创建黑洞"}</h3>
            <div class="row">
                <label>天体直径</label>
                <input type="number" id="dInp" min="4" value="${defaultD}" placeholder="最小4">
            </div>
            ${colorHtml}
            <div class="btnWrap">
                <button class="btn btnOk" id="okBtn">确定</button>
                <button class="btn btnCancel" id="cancelBtn">取消</button>
            </div>
        </div>`;
        **.body.appendChild(mask);

        const dInp = mask.querySelector('#dInp');
        const colorInp = mask.querySelector('#colorInp');
        const okBtn = mask.querySelector('#okBtn');
        const cancelBtn = mask.querySelector('#cancelBtn');

        // 取消
        cancelBtn.onclick = ()=>{
            mask.remove();
            resolve(null);
        };
        // 确定
        okBtn.onclick = ()=>{
            let d = parseFloat(dInp.value);
            if(isNaN(d) || d <4) d = defaultD;
            let c = defaultColor;
            if(isStar) c = colorInp.value;
            mask.remove();
            resolve({diameter:d,color:c});
        };
    });
}

class Star{
  constructor(x,y,diameter,colorHex){
    this.x = x;
    this.y = y;
    this.vx = (Math.random()-0.5)*1.2;
    this.vy = (Math.random()-0.5)*1.2;
    this.diameter = diameter;
    this.r = diameter / 2;
    this.m = diameter * 2.2;
    this.colorHex = colorHex;
    this.trail = [];
    this.alive = true;
  }
  absorbStar(m){
    this.m += m;
    this.diameter = this.m / 2.2;
    this.r = this.diameter / 2;
  }
  absorbBlackHole(m){
    this.m -= m * 0.6;
    if(this.m < 8) this.m = 8;
    this.diameter = this.m / 2.2;
    this.r = this.diameter / 2;
  }
  update(){
    let ax=0,ay=0;
    for(let s of stars){
      if(s === this || !s.alive) continue;
      let dx = s.x - this.x;
      let dy = s.y - this.y;
      let d = Math.hypot(dx, dy);
      d = Math.max(d, 12);
      let f = G * this.m * s.m / (d*d);
      ax += f * dx / d / this.m;
      ay += f * dy / d / this.m;
    }
    for(let bh of blackHoles){
      let dx = bh.x - this.x;
      let dy = bh.y - this.y;
      let d = Math.hypot(dx, dy);
      d = Math.max(d, 12);
      let f = G * this.m * bh.m / (d*d);
      ax += f * dx / d / this.m;
      ay += f * dy / d / this.m;
    }
    if(isControlMode && selectedTarget === this){
      const keys = keyState;
      if(keys.ArrowUp) ay -= controlForce;
      if(keys.ArrowDown) ay += controlForce;
      if(keys.ArrowLeft) ax -= controlForce;
      if(keys.ArrowRight) ax += controlForce;
    }

    this.vx += ax * speed;
    this.vy += ay * speed;
    this.x += this.vx * speed;
    this.y += this.vy * speed;

    this.trail.push({x:this.x,y:this.y,alpha:1});
    if(this.trail.length>180) this.trail.shift();
    this.trail.forEach(p=>p.alpha *= 0.985);

    for(let s of stars){
      if(s === this || !s.alive) continue;
      let dis = Math.hypot(this.x - s.x, this.y - s.y);
      if(dis < this.r + s.r && this.m > s.m){
        this.absorbStar(s.m);
        s.alive = false;
      }
    }

    for(let bh of blackHoles){
      let dis = Math.hypot(this.x - bh.x, this.y - bh.y);
      if(dis < this.r + bh.r){
        if(this.m > bh.m){
          this.absorbBlackHole(bh.m);
          bh.m = 0;
        }else{
          bh.absorb(this.m);
          this.alive = false;
          break;
        }
      }
    }

    const bounceFactor = 0.98;
    if(this.x < this.r){
      this.x = this.r;
      this.vx *= -bounceFactor;
    }
    if(this.x > canvas.width - this.r){
      this.x = canvas.width - this.r;
      this.vx *= -bounceFactor;
    }
    if(this.y < this.r){
      this.y = this.r;
      this.vy *= -bounceFactor;
    }
    if(this.y > canvas.height - this.r){
      this.y = canvas.height - this.r;
      this.vy *= -bounceFactor;
    }
  }
  draw(){
    for(let i=1;i<this.trail.length;i++){
      const p1 = this.trail[i-1];
      const p2 = this.trail[i];
      ctx.beginPath();
      ctx.moveTo(p1.x,p1.y);
      ctx.lineTo(p2.x,p2.y);
      ctx.strokeStyle=this.colorHex;
      ctx.globalAlpha = p2.alpha * 0.4;
      ctx.stroke();
      ctx.globalAlpha = 1;
    }
    if(selectedTarget === this){
      ctx.beginPath();
      ctx.arc(this.x,this.y,this.r+6,0,Math.PI*2);
      ctx.strokeStyle = isControlMode ? "#00ff00" : "#ffffff";
      ctx.lineWidth=2;
      ctx.stroke();
    }
    ctx.beginPath();
    ctx.arc(this.x,this.y,this.r,0,Math.PI*2);
    ctx.fillStyle=this.colorHex;
    ctx.fill();
  }
}

class BlackHole{
  constructor(x,y,diameter){
    this.x = x;
    this.y = y;
    this.vx = 0;
    this.vy = 0;
    this.diameter = diameter;
    this.r = diameter / 2;
    this.m = diameter * 8;
    this.baseD = diameter;
    this.color = "#000000";
    this.ringColor = "#9944ff";
  }
  absorb(num){
    this.m += num;
    this.diameter = this.baseD + this.m / 12;
    this.r = this.diameter / 2;
  }
  update(){
    let ax=0,ay=0;
    for(let bh of blackHoles){
      if(bh === this || bh.m <= 0) continue;
      let dx = bh.x - this.x;
      let dy = bh.y - this.y;
      let d = Math.hypot(dx, dy);
      d = Math.max(d, 20);
      let f = G * this.m * bh.m / (d*d);
      ax += f * dx / d / this.m;
      ay += f * dy / d / this.m;
    }
    if(isControlMode && selectedTarget === this){
      const keys = keyState;
      if(keys.ArrowUp) ay -= controlForce;
      if(keys.ArrowDown) ay += controlForce;
      if(keys.ArrowLeft) ax -= controlForce;
      if(keys.ArrowRight) ax += controlForce;
    }

    this.vx += ax * speed;
    this.vy += ay * speed;
    this.x += this.vx * speed;
    this.y += this.vy * speed;

    for(let bh of blackHoles){
      if(bh === this || bh.m <= 0) continue;
      let dis = Math.hypot(this.x - bh.x, this.y - bh.y);
      if(dis < this.r + bh.r && this.m > bh.m){
        this.absorb(bh.m);
        bh.m = 0;
      }
    }

    const bounceFactor = 0.98;
    if(this.x < this.r){
      this.x = this.r;
      this.vx *= -bounceFactor;
    }
    if(this.x > canvas.width - this.r){
      this.x = canvas.width - this.r;
      this.vx *= -bounceFactor;
    }
    if(this.y < this.r){
      this.y = this.r;
      this.vy *= -bounceFactor;
    }
    if(this.y > canvas.height - this.r){
      this.y = canvas.height - this.r;
      this.vy *= -bounceFactor;
    }
  }
  draw(){
    if(selectedTarget === this){
      ctx.beginPath();
      ctx.arc(this.x,this.y,this.r+8,0,Math.PI*2);
      ctx.strokeStyle = isControlMode ? "#00ff00" : "#ffffff";
      ctx.lineWidth=2;
      ctx.stroke();
    }
    ctx.beginPath();
    ctx.arc(this.x,this.y,this.r+14,0,Math.PI*2);
    ctx.fillStyle = this.ringColor;
    ctx.globalAlpha=0.28;
    ctx.fill();
    ctx.globalAlpha=1;
    ctx.beginPath();
    ctx.arc(this.x,this.y,this.r,0,Math.PI*2);
    ctx.fillStyle=this.color;
    ctx.fill();
  }
}

**.addEventListener('keydown',e=>{
  keyState[e.key] = true;
  if(e.key.toLowerCase()==='c'){
    stars = [];
    blackHoles = [];
    selectedTarget = null;
    isControlMode = false;
  }
  if(e.key.toLowerCase()==='r'){
    if(selectedTarget) isControlMode = !isControlMode;
  }
  // Z加速 X减速
  if(e.key.toLowerCase()==='z') speed = Math.min(1.5, speed + 0.1);
  if(e.key.toLowerCase()==='x') speed = Math.max(0.2, speed - 0.1);
});
**.addEventListener('keyup',e=>{
  keyState[e.key] = false;
});

canvas.addEventListener('mousedown',async e=>{
  const mx = e.clientX;
  const my = e.clientY;
  if(e.button === 0){
    // 左键:判断是否点击天体
    let hit = null;
    for(let bh of blackHoles){
      if(bh.m <= 0) continue;
      let dis = Math.hypot(mx - bh.x, my - bh.y);
      if(dis < bh.r + 10){
        hit = bh;
        break;
      }
    }
    if(!hit){
      for(let s of stars){
        if(!s.alive) continue;
        let dis = Math.hypot(mx - s.x, my - s.y);
        if(dis < s.r + 10){
          hit = s;
          break;
        }
      }
    }
    if(hit){
      selectedTarget = hit;
      isControlMode = false;
    }else{
      // 空白创建恒星,弹窗直径+颜色
      const res = await openCreateModal(true,30,"#ffdd66");
      if(res){
        stars.push(new Star(mx, my, res.diameter, res.color));
      }
    }
  }else if(e.button === 2){
    // 右键创建黑洞,仅直径
    const res = await openCreateModal(false,36,"");
    if(res){
      blackHoles.push(new BlackHole(mx, my, res.diameter));
    }
  }
});
canvas.oncontextmenu = e=>e.preventDefault();

function loop(){
  ctx.fillStyle='rgba(0,0,12,0.12)';
  ctx.fillRect(0,0,canvas.width,canvas.height);
  stars = stars.filter(s=>s.alive);
  blackHoles = blackHoles.filter(b=>b.m>0);
  blackHoles.forEach(bh=>{bh.update();bh.draw();});
  stars.forEach(s=>{s.update();s.draw();});
  requestAnimationFrame(loop);
}
loop();

window.onresize=()=>{
  canvas.width=innerWidth;
  canvas.height=innerHeight;
}
</**>
</body>
</html>
陆梓骞在2026-07-10 09:52:09追加了内容

打开教程:

桌面--》右键--》新建--》文本文档--》打开文本文档--》复制上面的代码--》粘贴到文本文档--》文件--》另存为--》保存名为 恒星模拟器v11.html --》

点击

改为所有文件

保存到桌面

点进去就可以使用了


0
已采纳
汪思源
汪思源
新手光能
新手光能

这种是本地的,其他人电脑打不开

0
0
0
0
杨文轩
杨文轩
高级光能
高级光能

shui shen me ne ,tian tian shui ,wei shen me yao shui ne ,shui hen hao wan ma ?

0
高驰宇
高驰宇
新手天翼
新手天翼

这个你直接把代码发出来吧

0
0
我要回答