为什么圆圈会在碰撞时振动(画布) [英] Why circles are vibrating on collision (Canvas)

查看:86
本文介绍了为什么圆圈会在碰撞时振动(画布)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have been creating a clone of agar.io and I don't understand why the circles start vibrating when they touch each other. Below is my code:

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();

body {
  margin: 0;
  padding: 0;
}

<canvas id="game">kindly update your browser.</canvas>

推荐答案

分隔圈



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

Separating circles

Your separation code was not correct. Use the vector between them to get the new pos.

查找两个圈子正在拦截从一个到另一个找到向量的长度

To find if two circles are intercepting find the length of the vector from one to the next

这两个圈子。

var cir1 = {x : 100, y : 100, r : 120}; // r is the radius
var cir2 = {x : 250, y : 280, r : 150}; // r is the radius

来自 cir2的向量 cir1

var vx = cir2.x - cir1.x;
var vy = cir2.y - cir1.y;

向量的长度

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

如果半径之和大于它们之间的向量长度,则圆圈会重叠

The circles overlap if the sum of the radii is greater than the length of the vector between them

if(cir1.r + cir2.r > len){ // circles overlap



规范化向量



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

Normalise the vector

If they overlap you need to move one away from the other. There are many ways to do this, the simplest way is to move one circle along the line between them.

首先从 cir1 <归一化矢量 cir2 除以它的(向量)长度。

First normalise the vector from cir1 to cir2 by dividing by its (vector) length.

    vx \= len;
    vy \= len;

请注意,长度可以为零。如果发生这种情况,那么在进一步的计算中你将获得 NaN 。如果你怀疑你可能在同一个位置得到一个圆圈,最简单的处理零点的方法是移动一个圆圈。

Note that the length could be zero. If this happens then you will get NaN in further calculations. If you suspect you may get one circle at the same location as another the easiest way to deal with the zero move one circle a little.

    // 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;
    }



将圈数移至



现在你有一个1个单位长的规范化向量,你可以通过乘以两个标量 vx vy 具有所需长度,在这种情况下是两个圆半径的总和。

Move circle/s to just touch

Now you have the normalised vector which is 1 unit long you can make it any length you need by multiplying the two scalars vx, vy with the desired length which in this case is the sum of the two circles radii.

    var mx = vx * (cir1.r + cir2.r);  // move distance
    var my = vy * (cir1.r + cir2.r);

仅使用以下方法之一

您现在可以将其中一个圆圈定位到正确的距离,以便它们只需触摸

You can now position one of the circles the correct distance so that they just touch

   // move cir1
   cir1.x = cir2.x - mx;
   cir1.y = cir2.y - my;






移动第二个圆圈

   cir2.x = cir1.x + mx;
   cir2.y = cir1.y + my;






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


Or move both circles but you will have to first find the proportional center between the two

   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     

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

Then move both circles away from that point by their radii

   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;     



DEMO



OP的代码段复制件mods通过移动第一个圆 blob1 远离第二个 blob2 并假设它们永远不会出现在相同点(不除零)

DEMO

Copy of OP's snippet with mods to fix problem by moving the the first circle blob1 away from the second blob2 and assuming they will never be at the same spot (no divide by zero)

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 x = blob2.x - blob1.x; // get the vector from blob1 to blob2
            var y = blob2.y - blob1.y; //
            var dist = Math.sqrt(x * x + y * y); // get the distance between the two blobs

            if (dist < blob1.mass + blob2.mass) {  // if the distance is less than the 2 radius
             // if there is overlap move blob one along the line between the two the distance of the two radius
              x /= dist; // normalize the vector. This makes the vector 1 unit long
              y /= dist;
              // multiplying the normalised vector by the correct distance between the two 
              // and subtracting that distance from the blob 2 give the new pos of 
              // blob 1
              blob1.x = blob2.x - x * (blob1.mass + blob2.mass);
              blob1.y = blob2.y - y * (blob1.mass + blob2.mass);
            }
          }
        }
      }

      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();

body {
  margin: 0;
  padding: 0;
}

<canvas id="game">kindly update your browser.</canvas>

这篇关于为什么圆圈会在碰撞时振动(画布)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆