[英]Why are my objects overlapping in my p5.js project?
我正在做一个用球模拟物理的项目。 这是项目的 p5 编辑器的链接。
我的问题如下,当我添加很多球(比如 200 个)时,球在堆积,但其中一些最终会塌陷,我不知道为什么。
有人可以解释它为什么这样做以及如何解决这个问题吗?
谢谢。
这是草图的代码。
document.oncontextmenu = function () {
return false;
}
let isFlushing = false;
let isBallDiameterRandom = false;
let displayInfos = true;
let displayWeight = false;
let clickOnce = false;
let FRAME_RATE = 60;
let SPEED_FLUSH = 3;
let Y_GROUND;
let lastFR;
let balls = [];
function setup() {
frameRate(FRAME_RATE);
createCanvas(window.innerWidth, window.innerHeight);
Y_GROUND = height / 20 * 19;
lastFR = FRAME_RATE;
}
function draw() {
background(255);
if (isFlushing) {
for (let i = 0; i < SPEED_FLUSH; i++) {
balls.pop();
}
if (balls.length === 0) {
isFlushing = false;
}
}
balls.forEach(ball => {
ball.collide();
ball.move();
ball.display(displayWeight);
ball.checkCollisions();
});
if (mouseIsPressed) {
let ballDiameter;
if (isBallDiameterRandom) {
ballDiameter = random(15, 101);
} else {
ballDiameter = 25;
}
if (canAddBall(mouseX, mouseY, ballDiameter)) {
isFlushing = false;
let newBall = new Ball(mouseX, mouseY, ballDiameter, balls);
if (mouseButton === LEFT && !clickOnce) {
balls.push(newBall);
clickOnce = true;
}
if (mouseButton === RIGHT) {
balls.push(newBall);
}
}
}
drawGround();
if (displayInfos) {
displayShortcuts();
displayFrameRate();
displayBallCount();
}
}
function mouseReleased() {
if (mouseButton === LEFT) {
clickOnce = false;
}
}
function keyPressed() {
if (keyCode === 32) {//SPACE
displayInfos = !displayInfos;
}
if (keyCode === 70) {//F
isFlushing = true;
}
if (keyCode === 71) {//G
isBallDiameterRandom = !isBallDiameterRandom;
}
if (keyCode === 72) {//H
displayWeight = !displayWeight;
}
}
function canAddBall(x, y, d) {
let isInScreen =
y + d / 2 < Y_GROUND &&
y - d / 2 > 0 &&
x + d / 2 < width &&
x - d / 2 > 0;
let isInAnotherBall = false;
for (let i = 0; i < balls.length; i++) {
let d = dist(x, y, balls[i].position.x, balls[i].position.y);
if (d < balls[i].w) {
isInAnotherBall = true;
break;
}
}
return isInScreen && !isInAnotherBall;
}
function drawGround() {
strokeWeight(0);
fill('rgba(200,200,200, 0.25)');
rect(0, height / 10 * 9, width, height / 10);
}
function displayFrameRate() {
if (frameCount % 30 === 0) {
lastFR = round(frameRate());
}
textSize(50);
fill(255, 0, 0);
let lastFRWidth = textWidth(lastFR);
text(lastFR, width - lastFRWidth - 25, 50);
textSize(10);
text('fps', width - 20, 50);
}
function displayBallCount() {
textSize(50);
fill(255, 0, 0);
text(balls.length, 10, 50);
let twBalls = textWidth(balls.length);
textSize(10);
text('balls', 15 + twBalls, 50);
}
function displayShortcuts() {
let hStart = 30;
let steps = 15;
let maxTW = 0;
let controlTexts = [
'LEFT CLICK : add 1 ball',
'RIGHT CLICK : add 1 ball continuously',
'SPACE : display infos',
'F : flush balls',
'G : set random ball diameter (' + isBallDiameterRandom + ')',
'H : display weight of balls (' + displayWeight + ')'
];
textSize(11);
fill(0);
for (let i = 0; i < controlTexts.length; i++) {
let currentTW = textWidth(controlTexts[i]);
if (currentTW > maxTW) {
maxTW = currentTW;
}
}
for (let i = 0; i < controlTexts.length; i++) {
text(controlTexts[i], width / 2 - maxTW / 2 + 5, hStart);
hStart += steps;
}
fill(200, 200, 200, 100);
rect(width / 2 - maxTW / 2,
hStart - (controlTexts.length + 1) * steps,
maxTW + steps,
(controlTexts.length + 1) * steps - steps / 2
);
}
这是 Ball class 的代码。
class Ball {
constructor(x, y, w, e) {
this.id = e.length;
this.w = w;
this.e = e;
this.progressiveWidth = 0;
this.rgb = [
floor(random(0, 256)),
floor(random(0, 256)),
floor(random(0, 256))
];
this.mass = w;
this.position = createVector(x + random(-1, 1), y);
this.velocity = createVector(0, 0);
this.acceleration = createVector(0, 0);
this.gravity = 0.2;
this.friction = 0.5;
}
collide() {
for (let i = this.id + 1; i < this.e.length; i++) {
let dx = this.e[i].position.x - this.position.x;
let dy = this.e[i].position.y - this.position.y;
let distance = sqrt(dx * dx + dy * dy);
let minDist = this.e[i].w / 2 + this.w / 2;
if (distance < minDist) {
let angle = atan2(dy, dx);
let targetX = this.position.x + cos(angle) * minDist;
let targetY = this.position.y + sin(angle) * minDist;
this.acceleration.set(
targetX - this.e[i].position.x,
targetY - this.e[i].position.y
);
this.velocity.sub(this.acceleration);
this.e[i].velocity.add(this.acceleration);
//TODO : Effets bizarre quand on empile les boules (chevauchement)
this.velocity.mult(this.friction);
}
}
}
move() {
this.velocity.add(createVector(0, this.gravity));
this.position.add(this.velocity);
}
display(displayMass) {
if (this.progressiveWidth < this.w) {
this.progressiveWidth += this.w / 10;
}
stroke(0);
strokeWeight(2);
fill(this.rgb[0], this.rgb[1], this.rgb[2], 100);
ellipse(this.position.x, this.position.y, this.progressiveWidth);
if (displayMass) {
strokeWeight(1);
textSize(10);
let tempTW = textWidth(int(this.w));
text(int(this.w), this.position.x - tempTW / 2, this.position.y + 4);
}
}
checkCollisions() {
if (this.position.x > width - this.w / 2) {
this.velocity.x *= -this.friction;
this.position.x = width - this.w / 2;
} else if (this.position.x < this.w / 2) {
this.velocity.x *= -this.friction;
this.position.x = this.w / 2;
}
if (this.position.y > Y_GROUND - this.w / 2) {
this.velocity.x -= this.velocity.x / 100;
this.velocity.y *= -this.friction;
this.position.y = Y_GROUND - this.w / 2;
} else if (this.position.y < this.w / 2) {
this.velocity.y *= -this.friction;
this.position.y = this.w / 2;
}
}
}
当球的质量总和大于球的弹性时,我看到这种重叠发生。 至少看起来是这样。 我用较小的池制作了一个副本,因此重现问题不需要太多时间。
在下面的示例中,有 6 个球(质量为 150 个单位)压在基排上,我们看到基排中的 13 个球重叠。 基行的宽度约为。 300 像素,仅够容纳 12 个直径为 25 的球。我认为这显示了 model 的局限性:球显示为圆形,但确实有一定的弹性,它们应该显示变形。 很难说如何在不实现绘制复杂形状的情况下解决此问题。 也许摩擦更少?
顺便说一句:你在那里建造的伟大的物理引擎:-)
与此同时,我可以用更少的球制作另一个截图。 其中三个(eq. 75 个单位)的重量足以在基行中产生重叠。
我将球的大小加倍并更改了水池的尺寸,以发现引擎中存在更严重的错误。 我看到球在压力下受到如此沉重的压力,以至于它们的“体积”(面积)没有足够的空间。 要么他们必须内爆,要么它的弹性反作用力必须对整个场景产生更大的影响。 如果你仔细观察底部空间最小的球的钟摆运动,你会发现它们非常猛烈,但显然没有机会到达外面。
难道是你的评价令
balls.forEach(ball => {
ball.collide();
ball.move();
ball.display(displayWeight);
ball.checkCollisions();
});
无法以现实的方式传播碰撞?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.