【发布时间】:2018-07-14 04:12:39
【问题描述】:
我正在尝试使用 p5.js 在 JavaScript 中构建类似的东西:
我能够检测到两个圆之间的碰撞,我正在尝试使用来自维基百科的这些(二维弹性碰撞)公式计算新速度: 对于 theta 和 phi 的这些角度:
问题似乎是当我计算新速度时,球已经碰撞/重叠并且它们被卡住了。我认为我应该做的是根据圆圈重叠的距离计算一个新的圆圈位置。不幸的是,我不知道该怎么做。我也认为我计算的方式过于复杂和低效。 这是我的碰撞处理代码的样子:
// takes ball object as input, sets speedvector to new x,y speed
collision(other) {
var newSpeed = createVector();
var phi = Math.atan((this.pos.y - other.pos.y) / this.pos.x - other.pos.x);
var theta1 = this.speed.heading();
var theta2 = other.speed.heading();
newSpeed.x = (this.speed.mag() * Math.cos(theta1 - phi) * (this.mass - other.mass) + 2 * other.mass * other.speed.mag() * Math.cos(theta2 - phi)) / (this.mass + other.mass) * Math.cos(phi) - this.speed.mag() * Math.sin(theta1 - phi) * Math.sin(phi);
newSpeed.y = (this.speed.mag() * Math.cos(theta1 - phi) * (this.mass - other.mass) + 2 * other.mass * other.speed.mag() * Math.cos(theta2 - phi)) / (this.mass + other.mass) * Math.sin(phi) + this.speed.mag() * Math.sin(theta1 - phi) * Math.cos(phi);
this.speed.x = newSpeed.x;
this.speed.y = newSpeed.y;
}
完整的代码示例:
var balls = [];
var numOfBalls = 5;
var maxSpeed = 2;
function setup() {
createCanvas(500, 500);
for (var i = 0; i < numOfBalls; i++) {
var ball = new Ball(30);
balls.push(ball);
}
}
function draw() {
background(0);
for (var i = 0; i < balls.length; i++) {
balls[i].move();
}
for (var i = 0; i < balls.length; i++) {
balls[i].show();
}
}
class Ball {
constructor(radius) {
this.radius = radius;
this.pos = this.pickLocation();
this.speed = createVector(random(-maxSpeed, maxSpeed), random(-maxSpeed, maxSpeed));
this.mass = 1;
}
pickLocation() {
//spawn within canvas
var xOption = random(this.radius, width - this.radius);
var yOption = random(this.radius, height - this.radius);
// check whether spawning on this location doesn't overlap other circles
for(var i = 0; i < balls.length; i++) {
// don't check for current circle
if(balls[i] != this) {
// get distance to other circle
var d = dist(xOption, yOption, balls[i].pos.x, balls[i].pos.y);
// check whether overlapping
if (d <= this.radius + balls[i].radius) {
// generate new location and rerun check
console.log("overlapping another circle, trying new location");
var xOption = random(this.radius, width - this.radius);
var yOption = random(this.radius, height - this.radius);
i = -1;
}
}
}
return(createVector(xOption, yOption));
}
move() {
for (var i = 0; i < balls.length; i++) {
if(balls[i] != this) {
var d = dist(this.pos.x, this.pos.y, balls[i].pos.x, balls[i].pos.y);
if(d < this.radius + balls[i].radius) {
this.collision(balls[i]);
}
}
}
if(this.pos.x - this.radius < 0 || this.pos.x + this.radius > width) {
this.speed.x *= -1;
}
if(this.pos.y - this.radius < 0 || this.pos.y + this.radius > height) {
this.speed.y *= -1;
}
this.pos.x += this.speed.x;
this.pos.y += this.speed.y;
}
// takes ball object as input, sets speedvector to new x,y speed
collision(other) {
var newSpeed = createVector();
var phi = Math.atan((this.pos.y - other.pos.y) / this.pos.x - other.pos.x);
var theta1 = this.speed.heading();
var theta2 = other.speed.heading();
newSpeed.x = (this.speed.mag() * Math.cos(theta1 - phi) * (this.mass - other.mass) + 2 * other.mass * other.speed.mag() * Math.cos(theta2 - phi)) / (this.mass + other.mass) * Math.cos(phi) - this.speed.mag() * Math.sin(theta1 - phi) * Math.sin(phi);
newSpeed.y = (this.speed.mag() * Math.cos(theta1 - phi) * (this.mass - other.mass) + 2 * other.mass * other.speed.mag() * Math.cos(theta2 - phi)) / (this.mass + other.mass) * Math.sin(phi) + this.speed.mag() * Math.sin(theta1 - phi) * Math.cos(phi);
this.speed.x = newSpeed.x;
this.speed.y = newSpeed.y;
}
show() {
fill(200, 100);
noStroke();
ellipse(this.pos.x, this.pos.y, this.radius * 2);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>
【问题讨论】:
-
请提供一个minimal reproducible example 来说明问题。另外:当两个以上的圆相撞时,您如何处理?
-
也许你可以给每个球一个 id 并存储最后一个球的 id,忽略与那个球的碰撞(在墙壁反弹时清除它?)
-
@KevinWorkman 我添加了示例。这应该在与 p5.js 结合的 HTML 文件中导入(我正在使用此链接:cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.9/p5.min.js)。我还没有想过如何处理两个以上的圆圈碰撞。如果我能从两个圈子开始,我会很高兴。
-
你试过调试你的程序吗?哪一行代码的行为与您的预期不同?
-
@KevinWorkman 我试过了。例如,我确定我的对象速度矢量在碰撞后正在更新。但是,如果您能推荐一个非常有帮助的教程,我从未接受过任何有关编程的教育。我希望我的对象在碰撞后会改变方向,但我认为由于它们重叠(少量重叠),它们会不断碰撞,从而粘在一起并不断改变方向。我认为碰撞发生在帧之间,我应该计算发生碰撞的点并相应地更新对象位置。
标签: javascript collision geometry p5.js