问题标题: 盐都不盐了

0
1
陆梓骞
陆梓骞
新手守护
新手守护

陆梓骞在2026-07-18 09:30:48追加了内容

我一进来就看见

何意味?

酷丁平台好像没有说不能回复两周以上的贴子吧

陆梓骞在2026-07-18 09:33:30追加了内容

切入正题

陆梓骞在2026-07-18 09:36:29追加了内容
<!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[type="number"]{
    padding:6px;width:180px;font-size:14px;
    background:#2c2c44;
    color:#ffffff;
    border:1px solid #555;
    border-radius:4px;
}
/* 占位符浅灰 */
.row input[type="number"]::placeholder{
    color:#bbbbbb;
}
.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-18 09:37:33追加了内容

这是恒星模拟器v12,不会用的看我之前的帖

陆梓骞在2026-07-18 09:52:55追加了内容

@于行衍 

陆梓骞在2026-07-18 09:54:17追加了内容

陆梓骞在2026-07-18 09:54:59追加了内容

陆梓骞在2026-07-18 09:56:13追加了内容


1
李皓辰
李皓辰
高级守护
高级守护

可是你回答的问题都是什么时候的呢?

2021.12.25

2022.12.9

2025.11.22

全都挖坟了呀,希望你引以为戒

1
于行衍
于行衍
高级天翼
高级天翼

不是,你没挖坟别人为啥说你呢,就算一个人说你是他脑子不好,但是这么多人骂你还能是他们的问题吗?

你来问答就有遵守问答的规矩,别在这犟

0
王旭邈
王旭邈
中级天翼
中级天翼

问答之前是明确写过不能回复2周及以上贴子的,只不过后来不知道什么时候删了

总之这就叫挖坟,是不对的

0
范聿舟
范聿舟
高级光能
高级光能

所以你为什么要挖坟,看在你还是新手的份上我就不刷你了

0
李皓辰
李皓辰
高级守护
高级守护

回复老帖会导致帖子上浮,比如你回答了几年前的帖子,就会导致那个帖子置顶

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

同学,不要挖坟哦,挖坟指的是回复2个星期及之前的老帖子,会导致旧帖子上浮,覆盖原来的新帖子(你的帖子刚发上去就被刷下来,你气不气)

0
0
我要回答