为什么圆圈会在碰撞时振动(画布)

10 javascript canvas

我一直在创建一个agar.io的克隆,我不明白为什么这些圆圈在相互接触时会开始振动.以下是我的代码:

var
  canvas,
  ctx,
  width = innerWidth,
  height = innerHeight,
  mouseX = 0,
  mouseY = 0;

var

  camera = {
    x: 0,
    y: 0,

    update: function(obj) {
      this.x = obj.x - width / 2;
      this.y = obj.y - height / 2;
    }
  },

  player = {
    defaultMass: 54,
    x: 0,
    y: 0,
    blobs: [],

    update: function() {
      for (var i = 0; i < this.blobs.length; i++) {
        var x = mouseX + camera.x - this.blobs[i].x;
        var y = mouseY + camera.y - this.blobs[i].y;
        var length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        var speed = 54 / this.blobs[i].mass;

        this.blobs[i].velX = x / length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));
        this.blobs[i].velY = y / length * speed * Math.min(1, Math.pow(x / this.blobs[i].mass, 2));

        this.blobs[i].x += this.blobs[i].velX;
        this.blobs[i].y += this.blobs[i].velY;

        for (var j = 0; j < this.blobs.length; j++) {
          if (j != i && this.blobs[i] !== undefined) {
            var blob1 = this.blobs[i];
            var blob2 = this.blobs[j];
            var dist = Math.sqrt(Math.pow(blob2.x - blob1.x, 2) + Math.pow(blob2.y - blob1.y, 2));

            if (dist < blob1.mass + blob2.mass) {
              if (this.blobs[i].x < this.blobs[j].x) {
                this.blobs[i].x--;
              } else if (this.blobs[i].x > this.blobs[j].x) {
                this.blobs[i].x++;
              }
              if (this.blobs[i].y < this.blobs[j].y) {
                this.blobs[i].y--;
              } else if ((this.blobs[i].y > this.blobs[j].y)) {
                this.blobs[i].y++;
              }
            }
          }
        }
      }

      this.x += (mouseX - width / 2) / (width / 2) * 1;
      this.y += (mouseY - height / 2) / (height / 2) * 1
    },

    split: function(cell) {
      cell.mass /= 2;

      this.blobs.push({
        x: cell.x,
        y: cell.y,
        mass: cell.mass
      });
    },

    draw: function() {
      for (var i = 0; i < this.blobs.length; i++) {
        ctx.fillStyle = "red";

        ctx.beginPath();
        ctx.arc(-camera.x + this.blobs[i].x, -camera.y + this.blobs[i].y, this.blobs[i].mass, 0, Math.PI * 2);
        ctx.fill();
        ctx.closePath();
      }
    }
  };

function handleMouseMove(e) {
  mouseX = e.clientX;
  mouseY = e.clientY;
}

function setup() {
  canvas = document.getElementById("game");
  ctx = canvas.getContext("2d");
  canvas.width = width;
  canvas.height = height;

  addEventListener("mousemove", handleMouseMove);

  player.blobs.push({
    x: 0,
    y: 0,
    mass: player.defaultMass
  });
  player.blobs.push({
    x: 100,
    y: 100,
    mass: player.defaultMass / 2
  });
  player.blobs.push({
    x: 100,
    y: 100,
    mass: player.defaultMass * 2
  });

  var loop = function() {
    update();
    draw();
    requestAnimationFrame(loop);
  }
  requestAnimationFrame(loop);
}

function update() {
  camera.update(player.blobs[0]);
  player.update();
}

function draw() {
  ctx.fillStyle = "#fff";
  ctx.fillRect(0, 0, width, height);

  player.draw();
}

setup();
Run Code Online (Sandbox Code Playgroud)
body {
  margin: 0;
  padding: 0;
}
Run Code Online (Sandbox Code Playgroud)
<canvas id="game">kindly update your browser.</canvas>
Run Code Online (Sandbox Code Playgroud)

Bli*_*n67 3

分隔圆圈

您的分隔代码不正确。使用它们之间的向量来获取新的位置。

它们之间的向量

要确定两个圆是否相交,请找出从一个圆到下一个圆的向量的长度

两个圆圈。

var cir1 = {x : 100, y : 100, r : 120}; // r is the radius
var cir2 = {x : 250, y : 280, r : 150}; // r is the radius
Run Code Online (Sandbox Code Playgroud)

向量从cir2cir1

var vx = cir2.x - cir1.x;
var vy = cir2.y - cir1.y;
Run Code Online (Sandbox Code Playgroud)

向量的长度

var len = Math.sqrt(x * x + y * y);
// or use the ES6 Math.hypot function
/* var len = Math.hypot(x,y); */
Run Code Online (Sandbox Code Playgroud)

如果半径之和大于圆之间矢量的长度,则圆重叠

if(cir1.r + cir2.r > len){ // circles overlap
Run Code Online (Sandbox Code Playgroud)

标准化向量

如果它们重叠,您需要将其中一个远离另一个。有很多方法可以做到这一点,最简单的方法是沿着它们之间的线移动一个圆圈。

首先通过除以向量的(向量)长度来标准化向量从cir1到 的值。cir2

    vx \= len;
    vy \= len;
Run Code Online (Sandbox Code Playgroud)

请注意,长度可以为零。如果发生这种情况,您将进行NaN进一步的计算。如果您怀疑您可能会在与另一个圆相同的位置得到一个圆,那么处理零的最简单方法是稍微移动一个圆。

    // replace the two lines above with
    if(len === 0){ // circles are on top of each other
        vx = 1;  // move the circle (abstracted into the vector)
    }else{
        vx \= len;  // normalise the vector
        vy \= len;
    }
Run Code Online (Sandbox Code Playgroud)

移动圆圈即可触摸

vx现在您有了 1 个单位长的归一化向量,您可以通过将两个标量乘以所需的长度(vy在本例中为两个圆半径之和)来使其成为所需的任何长度。

    var mx = vx * (cir1.r + cir2.r);  // move distance
    var my = vy * (cir1.r + cir2.r);
Run Code Online (Sandbox Code Playgroud)

仅使用以下方法之一

现在,您可以将其中一个圆圈放置在正确的距离处,以便它们刚好接触

   // move cir1
   cir1.x = cir2.x - mx;
   cir1.y = cir2.y - my;
Run Code Online (Sandbox Code Playgroud)

或者移动第二个圆圈

   cir2.x = cir1.x + mx;
   cir2.y = cir1.y + my;
Run Code Online (Sandbox Code Playgroud)

或者移动两个圆,但你必须首先找到两个圆之间的比例中心

   var pLen = cir1.r / (cir1.r + cir2.r); // find the ratio of the radii
   var cx = cir1.x + pLen * vx * len;  // find the proportional center between
   var cy = cir1.y + pLen * vy * len;  // the two circles     
Run Code Online (Sandbox Code Playgroud)

然后将两个圆从该点移开其半径

   cir1.x = cx - vx * cir1.r;     // move circle 1 away from the shared center
   cir1.y = cy - vy * cir1.r;     
   cir2.x = cx + vx * cir2.r;     // move circle 2 away from the shared center
   cir2.y = cy + vy * cir2.r;     
Run Code Online (Sandbox Code Playgroud)

演示版

带有 mods 的 OP 代码片段的副本,通过将第一个圆圈移blob1离第二个圆圈blob2并假设它们永远不会位于同一位置(不除以零)来解决问题

var cir1 = {x : 100, y : 100, r : 120}; // r is the radius
var cir2 = {x : 250, y : 280, r : 150}; // r is the radius
Run Code Online (Sandbox Code Playgroud)
var vx = cir2.x - cir1.x;
var vy = cir2.y - cir1.y;
Run Code Online (Sandbox Code Playgroud)
var len = Math.sqrt(x * x + y * y);
// or use the ES6 Math.hypot function
/* var len = Math.hypot(x,y); */
Run Code Online (Sandbox Code Playgroud)