javascript - p5.j​​s 中的 Angular 碰撞 Angular

标签 javascript processing collision-detection physics p5.js

总结:

为了尝试在移动的矩形和下落的圆圈之间制作一个简单的碰撞检测系统,我想让它更逼真。

主要问题:

-我想解决的主要问题是检测圆对象何时击中矩形的 Angular ,并根据该 Angular 使圆反弹。

代码:

var balls = [];
var obstacle;

function setup() {
  createCanvas(400, 400);
  obstacle = new Obstacle();
}

function draw() {
  background(75);
  obstacle.display();
  obstacle.update();
  
  for (var i = 0; i < balls.length; i++) {
    balls[i].display();
	  if (!RectCircleColliding(balls[i], obstacle)){
        balls[i].update();
        balls[i].edges();
	  }
    
    //console.log(RectCircleColliding(balls[i], obstacle));
  }
}

function mousePressed() {
  balls.push(new Ball(mouseX, mouseY));
}

function Ball(x, y) {
  this.x = x;
  this.y = y;
  this.r = 15;
  this.gravity = 0.5;
  this.velocity = 0;
  this.display = function() {
    fill(255, 0, 100);
    stroke(255);
    ellipse(this.x, this.y, this.r * 2);
  }
  this.update = function() {
    this.velocity += this.gravity;
    this.y += this.velocity;
  }
  this.edges = function() {
    if (this.y >= height - this.r) {
      this.y = height - this.r;
      this.velocity = this.velocity * -1;
      this.gravity = this.gravity * 1.1;
    }
  }
}

function Obstacle() {
  this.x = width - width;
  this.y = height / 2;
  this.w = 200;
  this.h = 25;

  this.display = function() {
    fill(0);
    stroke(255);
    rect(this.x, this.y, this.w, this.h);
  }
  
  this.update = function() {
    this.x++;
    
    if (this.x > width + this.w /2) {
       this.x = -this.w;
    }
  }
}

function RectCircleColliding(Ball, Obstacle) {
  // define obstacle borders
  var oRight = Obstacle.x + Obstacle.w;
  var oLeft = Obstacle.x;
  var oTop = Obstacle.y;
  var oBottom = Obstacle.y + Obstacle.h;

  //compare ball's position (acounting for radius) with the obstacle's border
  if (Ball.x + Ball.r > oLeft) {
    if (Ball.x - Ball.r < oRight) {
      if (Ball.y + Ball.r > oTop) {
        if (Ball.y - Ball.r < oBottom) {
          
         let oldY = Ball.y;
         Ball.y = oTop - Ball.r;
         Ball.velocity = Ball.velocity * -1;
           if (Ball.gravity < 2.0){
              Ball.gravity = Ball.gravity * 1.1;  
           } else {
             Ball.velocity = 0;
             Ball.y = oldY;
         }   
         return (true);
        } 
      }
    }
  }
    return false;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>

预期输出:

我希望看到下落的圆圈相对于它们击中矩形的位置从矩形反弹。

如果圆圈撞到 Angular 落,它们应该以不同方式反弹,而不是撞到死点。

最佳答案

先决条件

球的速度必须是一个矢量(XY 分量),而不仅仅是一个数字。


1。确定圆圈是否会碰到边或 Angular

获取从矩形中心到圆的向量分量,并与矩形的尺寸进行比较:

// Useful temporary variables for later use
var hx = 0.5 * obstacle.w;
var hy = 0.5 * obstacle.h;
var rx = obstacle.x + hx;
var ry = obstacle.y + hy;

// displacement vector
var dx = ball.x - rx;
var dy = ball.y - ry;

// signs
var sx = dx < -hx ? -1 : (dx > hx ? 1 : 0);
var sy = dy < -hy ? -1 : (dy > hy ? 1 : 0);

如果 sx, sy 都不为零,则球可能会击中 Angular 落,否则可能会击中侧面。


2。判断圆是否碰撞

将每个符号乘以各自的半维:

// displacement vector from the nearest point on the rectangle
var tx = sx * (Math.abs(dx) - hx);
var ty = sy * (Math.abs(dy) - hy);

// distance from p to the center of the circle
var dc = Math.hypot(tx, ty);

if (dc <= ball.r) {
    /* they do collide */
}

3。确定碰撞法向量

(tx, ty) 是法向量的分量,但前提是球的中心位于矩形之外:

// epsilon to account for numerical imprecision
const EPSILON = 1e-6;

var nx = 0, ny = 0, nl = 0;
if (sx == 0 && sy == 0) {  // center is inside
  nx = dx > 0 ? 1 : -1;
  ny = dy > 0 ? 1 : -1;
  nl = Math.hypot(nx, ny);
} else {                   // outside
  nx = tx;
  ny = ty;
  nl = dc;
}
nx /= nl;
ny /= nl;

4。解决任何“渗透”

(请不要开不成熟的玩笑)

这确保球永远不会穿透矩形的表面,从而提高碰撞的视觉质量:

ball.x += (ball.r - dc) * nx; 
ball.y += (ball.r - dc) * ny;

5。解决碰撞

如果圆沿法线方向行进,则不要解决碰撞,因为球可能会粘在表面上:

// dot-product of velocity with normal
var dv = ball.vx * nx + ball.vy * ny;

if (dv >= 0.0) {
    /* exit and don't do anything else */
}

// reflect the ball's velocity in direction of the normal
ball.vx -= 2.0 * dv * nx;
ball.vy -= 2.0 * dv * ny;

工作 JS 片段

const GRAVITY = 250.0;

function Ball(x, y, r) {
  this.x = x;
  this.y = y;
  this.r = r;
  this.vx = 0;
  this.vy = 0;

  this.display = function() {
    fill(255, 0, 100);
    stroke(255);
    ellipse(this.x, this.y, this.r * 2);
  }

  this.collidePage = function(b) {
    if (this.vy > 0 && this.y + this.r >= b) {
      this.y = b - this.r;
      this.vy = -this.vy;
    }
  }

  this.updatePosition = function(dt) {
    this.x += this.vx * dt;
    this.y += this.vy * dt;
  }
  this.updateVelocity = function(dt) {
    this.vy += GRAVITY * dt;
  }
}

function Obstacle(x, y, w, h) {
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;

  this.display = function() {
    fill(0);
    stroke(255);
    rect(this.x, this.y, this.w, this.h);
  }

  this.update = function() {
    this.x++;
    if (this.x > width + this.w /2) {
      this.x = -this.w;
    }
  }
}

var balls = [];
var obstacle;

function setup() {
  createCanvas(400, 400);
  obstacle = new Obstacle(0, height / 2, 200, 25);
}

const DT = 0.05;

function draw() {
  background(75);
  obstacle.update();
  obstacle.display();
  for (var i = 0; i < balls.length; i++) {
    balls[i].updatePosition(DT);
    balls[i].collidePage(height);
    ResolveRectCircleCollision(balls[i], obstacle);
    balls[i].updateVelocity(DT);
    balls[i].display();
  }
}

function mousePressed() {
  balls.push(new Ball(mouseX, mouseY, 15));
}

const EPSILON = 1e-6;

function ResolveRectCircleCollision(ball, obstacle) {
  var hx = 0.5 * obstacle.w, hy = 0.5 * obstacle.h;
  var rx = obstacle.x + hx, ry = obstacle.y + hy;
  var dx = ball.x - rx, dy = ball.y - ry;

  var sx = dx < -hx ? -1 : (dx > hx ? 1 : 0);
  var sy = dy < -hy ? -1 : (dy > hy ? 1 : 0);

  var tx = sx * (Math.abs(dx) - hx);
  var ty = sy * (Math.abs(dy) - hy);
  var dc = Math.hypot(tx, ty);
  if (dc > ball.r)
    return false;

  var nx = 0, ny = 0, nl = 0;
  if (sx == 0 && sy == 0) {
    nx = dx > 0 ? 1 : -1; ny = dy > 0 ? 1 : -1;
    nl = Math.hypot(nx, ny);
  } else {
    nx = tx; ny = ty;
    nl = dc;
  }
  nx /= nl; ny /= nl;

  ball.x += (ball.r - dc) * nx; ball.y += (ball.r - dc) * ny;

  var dv = ball.vx * nx + ball.vy * ny;
  if (dv >= 0.0)
    return false;
  ball.vx -= 2.0 * dv * nx; ball.vy -= 2.0 * dv * ny;

  return true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>

关于javascript - p5.j​​s 中的 Angular 碰撞 Angular ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55419162/

相关文章:

javascript - 在 sigma.js 中布局图形时绘制边

javascript - 用于查找 Jquery 的 CPU 和内存使用情况的工具/插件

processing - 碰撞,当物体撞击另一个物体时如何使用碰撞

c++ - A* 跳跃点搜索——剪枝是如何真正起作用的?

平台游戏中的 XNA 碰撞检测

javascript - ES6 箭头表示法与 Jquery filter() 的关系?

javascript - super 喜欢可拖动 map

python - Python处理中是否有random.choices()函数

javascript - 在 javascript/p5.js 中查找与当前颜色最接近的索引颜色值

c++ - 地形碰撞问题