碰到障碍物时如何改变矢量的角度

How can I change the angle of a vector when hitting an obstacle

所以,我的问题与向量有关,我不知道我将如何处理这种情况。我正在构建大流行病模拟(使用 Javascript 和库 p5.js),并且我正在尝试添加锁定功能。

这是一张让一切更清晰的图片:

本质上,此时,当两个分子发生碰撞时,它们的速度矢量通过改变它们之前的速度而适当地改变。

} else {
            // dx & dy derivate  are equal to the difference of our molecules x & y coordinates
            let dx = this.position.x - _molecule.position.x;
            let dy = this.position.y - _molecule.position.y;

            // normalX & normalY are equal to theirs respective derivates divided by the distance
            let normalX = dx / _distance;
            let normalY = dy / _distance;

            // dVector is the vector which determine how the molecules will move appropiately on  x & y axis
            let dVector = (this.velocity.x - _molecule.velocity.x) * normalX;
            dVector += (this.velocity.y - _molecule.velocity.y) * normalY;

            // the molecules velocity is then  determined by the product of dVector by normalX & normalY
            let dvx = dVector * normalX;
            let dvy = dVector * normalY;

            // constrain limits the velocities between -1 & 1
            let constrainX = constrain(dvx, -1, 1);
            let constrainY = constrain(dvy, -1, 1);

            this.velocity.x -= constrainX;
            this.velocity.y -= constrainY;

            _molecule.velocity.x += constrainX;
            _molecule.velocity.y += constrainY;
        }

当我想在一个分子撞击另一个固定分子时改变矢量的角度时,我的问题就出现了。与上面的代码不同,固定分子必须保持静止。 因此,我假设我不能将 this.velocity.x (或 y)设置为简单地反转。

弹跳方法有两个参数:_molecule(或球B,球A碰撞的那个)和距离,计算如下:

let distance = dist(this.position.x, this.position.y, _molecule.position.x, _molecule.position.y)

我假设我必须使用正弦和余弦,但我不太确定。

我创建了 a tutorial on OpenProcessing,我认为它可以帮助您理解用于处理移动和静止圆形物体之间碰撞的矢量数学。简而言之,一个圆形物体与另一个圆形物体碰撞可以概括为该圆与另一个圆相切并垂直于一个圆心和另一个圆心的线的碰撞。

这是教程第 4 页的相关代码示例:

const radius = 30;
const speed = 100;

let pos;
let vel;
let time;

let boundary = [];
let obstacles = [];

function setup() {
  createCanvas(400, 400);
  angleMode(DEGREES);
  ellipseMode(RADIUS);

  boundary.push(createVector(60, 4));
  boundary.push(createVector(width - 4, 60));
  boundary.push(createVector(width - 60, height - 4));
  boundary.push(createVector(4, height - 60));

  obstacles.push(createVector(width / 2, height / 2));

  pos = createVector(
    random(40, width - 40),
    random(40, height - 40)
  );
  vel = createVector(100, 0).rotate(random(0, 360));
  time = millis();
}

function draw() {
  deltaT = millis() - time;
  time = millis();

  background('dimgray');

  push();
  fill('lightgray');
  stroke('black');
  strokeWeight(2);
  beginShape();
  for (let v of boundary) {
    vertex(v.x, v.y);
  }
  endShape(CLOSE);
  pop();

  // update position
  pos = createVector(
    min(max(0, pos.x + vel.x * (deltaT / 1000)), width),
    min(max(0, pos.y + vel.y * (deltaT / 1000)), height)
  );

  circle(pos.x, pos.y, radius);

  // check for collisions
  for (let i = 0; i < boundary.length; i++) {
    checkCollision(boundary[i], boundary[(i + 1) % boundary.length]);
  }

  push();
  fill('dimgray');
  for (let obstacle of obstacles) {
    circle(obstacle.x, obstacle.y, radius);

    // Find the tangent plane that is perpendicular to a line from the obstacle to
    // the moving circle

    // A vector pointing in the direction of the moving object
    let dirVector = p5.Vector.sub(pos, obstacle).normalize().mult(radius);

    // The point on the perimiter of the obstacle that is in the direction of the
    // moving object
    let p1 = p5.Vector.add(obstacle, dirVector);
    checkCollision(p1, p5.Vector.add(p1, p5.Vector.rotate(dirVector, -90)));
  }
  pop();
}

// Handles collision with a plane given two points on the plane.
// It is assumed that given a vector from p1 to p2, roating that vector
// clockwise 90 degrees will give a vector pointing to the in-bounds side of the
// plane (i.e. a "normal").
function checkCollision(p1, p2) {
  let boundaryVector = p5.Vector.sub(p2, p1);
  let objVector = p5.Vector.sub(pos, p1);
  let angle = boundaryVector.angleBetween(objVector);
  let dist = objVector.mag() * sin(angle);

  if (dist <= radius) {
    // Collision
    let vParallel = project(vel, boundaryVector);
    let vPerpendicular = p5.Vector.sub(vel, vParallel);

    vel = p5.Vector.add(vParallel, p5.Vector.mult(vPerpendicular, -1));

    let bounce = min(radius, radius - dist);
    // If the ball has crossed over beyond the plane we want to offset it to be on
    // the in-bounds side of the plane.
    let bounceOffset = p5.Vector.rotate(boundaryVector, 90).normalize().mult(bounce);
    pos.add(bounceOffset);
  }
}

function project(vect1, vect2) {
  vect2 = p5.Vector.normalize(vect2);
  return p5.Vector.mult(vect2, p5.Vector.dot(vect1, vect2));
}
<!DOCTYPE html>
<html lang="en">

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
</head>

<body>
</body>

</html>