It looks like you're new here. If you want to get involved, click one of these buttons!
Hello!
I'm relatively new to p5.js, and have been working on a physics simulation where I want to accurately simulate gravity in a window that allows for scaling units.
The problem I had was scaling such that I could set my gravity.y vector to 9.8, and have 1 meter = 1 pixel, such that the object accelerates down at 9.8px/x^2. However, at a frameRate of 60, there's problems. I discovered that I had to do G.mult(someFactor) to make it accurate. Here's the formula that made it work:
function fS(n) {
total = 0;
for (var i = 0; i <= n; i++) {
total += i;
}
return 1/(total*2);
}
someFactor = fS( frameRate() );
I also have a simScale variable that changes the meters/pixels ratio, and currently it's messing up the physics i.e it only produces the right outputs when its equal to 1 (1m = 1px). Here's the entire code, looking for suggestions as to how to improve.
=======================================
function fS(n) {
total = 0;
for (var i = 0; i <= n; i++) {
total += i;
}
return 1/(total*2);
}
function setup() {
counter = 0;
fR = 60;
frameRate(fR);
W = windowWidth;
H = windowHeight;
ground = H;
simScale = 1;
frameScale = fS(fR);
G = createVector(0, 9.8);
G.mult(simScale);
createCanvas(W, H);
ball = new Ball();
}
function draw() {
background(2);
ball.show();
counter++;
}
function Ball() {
this.r = 10;
this.dropHeight = 123 // height in meters you want to drop from
this.initHeight = ground - this.dropHeight - this.r;
this.pos = createVector(0, this.initHeight / simScale);
this.acceleration = createVector(0, 0);
this.velocity = createVector(0, 0);
this.altitude = ground - this.pos.y - this.r;
this.updatePos = function() {
var scaledG = p5.Vector.mult(G, frameScale);
this.acceleration.add(scaledG);
this.velocity.add(this.acceleration);
this.pos.add(this.velocity);
if (this.pos.y > ground - this.r) {
this.pos.y = ground - this.r;
noLoop();
}
this.altitude = ground - this.pos.y - this.r;
this.acceleration.mult(0);
}
this.show = function() {
this.updatePos();
ellipse(W/2, this.pos.y, this.r*2, this.r*2);
fill(200);
text("Scale: 1m = " + simScale + " px(s)", 200, 30);
text("Altitude: " + (this.altitude/simScale).toFixed(2) + " m", 20, 30);
text("Elapsed: " + (counter/fR).toFixed(2) + " s", 20, 50);
text("Displacement: " + Math.abs(this.initHeight - this.pos.y).toFixed(2) + " m", 20, 70);
text("Velocity: " + (this.velocity.y * fR).toFixed(2) + " m/s", 20, 90);
}
}
Answers
Looks like you're increasing the acceleration each frame.
Constant acceleration would be more accurate.
For each frame, I'm adding gravitational acceleration to the this.acceleration vector, and then applying that to the velocity vector, and then zeroing out this.acceleration
this.acceleration.mult(0)
, that way acceleration is constant, and velocity compounds.@lorensheets If you want an accurate simulation then don't rely on the framerate for animation timing. Instead use time-based animation.
:-O
THANKS!
@lorensheets you're right my bad
worth a read:
https://gafferongames.com/post/integration_basics
https://gafferongames.com/post/fix_your_timestep
some nice WebGL demos:
T_D, perfect, thank you. This is exactly what I need.