Physics simulator

Hello Processing Foundation.
I have started on a new processing project which is to code this projectile motion simulator:
https://ophysics.com/k8.html

This simulator shows the path of a ball when thrown at a specific launch angle, start height and initial velocity.
But unfortunately, I have no idea how to start the coding of this simulator and how to set up the data structure. Therefore, I hope to get a few tips on how to start coding this simulator.

1 Like

Well… You have 2 options from my point of view.

The first easy (and kinda lazy one) is numerical integration. Basically you have a single force acting on the projectile, which creates a constant acceleration (gravity, of an acceleration of around 9.81 m.s-2).

You could store position (as a PVector) as well as speed (as a PVector as well), then add onto velocity your acceleration times a small time step, and then add to your position your velocity times the same small time step. Here is a simple example (press enter to start it) :

PVector pos;
PVector speed;

float dt = 1./60.0;

ArrayList<PVector> trace;

boolean started = false;

void setup() {
  size(1280, 720);
  frameRate(60);
  pos = new PVector(10, height-10);
  speed = new PVector(90, -200);
  trace = new ArrayList<PVector>();
  trace.add(pos.copy());
}

void keyPressed(){
  if(key == ENTER) started = true;
}

void draw() {
  background(255);
  
  if(started){
    speed.add(PVector.mult(new PVector(0, 60), dt));
    pos.add(PVector.mult(speed, dt));
    trace.add(pos.copy());
  }
  
  noFill();
  stroke(0, 100);
  strokeWeight(2);
  beginShape();
  for(PVector v: trace){
    vertex(v.x, v.y);
  }
  endShape();
  
  fill(255, 0, 0);
  noStroke();
  ellipse(pos.x, pos.y, 10, 10);
  
  stroke(0);
  strokeWeight(1);
  line(pos.x, pos.y, pos.x, pos.y+0.4*speed.y);
  line(pos.x, pos.y, pos.x+0.4*speed.x, pos.y);
  
  strokeWeight(2);
  line(pos.x, pos.y, pos.x+0.4*speed.x, pos.y+0.4*speed.y);
}

This should work fine, and what is cool with integration is that you could as simply add all other types of forces (let’s say air resistance for example).

This is pretty imprecise though (as dt gets smaller, the precision gets better but the calculation time gets worse).

If you plan to only implement simple cases (constant acceleration or simple forms of air resistance) I advise to analytically integrate acceleration. In this case it is very easy and the solution is a linear function for x and a parabola for y. Here is the mathematical integration without air resistance:

Suppose p(t) is the position of the projectile at time t, given that p’’(t) = a = (0, ay), that p(0) = (px0, py0), and that p’(t) = (vx0, vy0), the first integration yields p’(t) = (vx0, ay * t + vy0) and the second,
p(t) = (vx0 * t + px0, ay * t^2 / 2 + vy0 * t + py0) (this last line is your projectile position, the one before is the projectile acceleration. You can in processing code speed and position functions, that are exactly defined as these two, and then either call them with increasing times or even go to any time.

If you want a more complex model, I advise to look this up for the analytical integration : Projectile motion - Wikipedia

Good luck ! :3

3 Likes

I made a similar project as r.jaoui. Feel free to use it as more reference!

Code
float x=100, y=400, xs=5, ys=-5, g=0.1, r = 5,dm = 10; //dm = display multiplier
boolean moving = false;
int len = 100;
ArrayList<PVector> trace = new ArrayList<PVector>();
void setup() {
  size(600,600);
}
void draw() {
  background(0);
  stroke(255);
  if(moving) {
    ys += g;
    x += xs;
    y += ys;
    trace.add(new PVector(x,y));
    if(trace.size() > len && len != -1) trace.remove(0);
  }
  circle(x,y,r*2);
  line(x,y,x+xs*dm,y+ys*dm);
  line(x,y,x+xs*dm,y);
  line(x,y,x,y+ys*dm);
  displayTrace();
}
void displayTrace() {
  pushStyle();
  noFill();
  stroke(255,50);
  beginShape();
  for(int i = 0; i < trace.size(); i++) vertex(trace.get(i).x,trace.get(i).y);
  endShape();
  popStyle();
}

void keyPressed() { moving = !moving; }
2 Likes

Thank you very much @r.jaoui and @CodeMasterX for your help. My project is going very well and i am making a lot of progress :slight_smile:

Right now I am trying to incorporate these two functions into the position and speed PVector, so my simulator will match real conditions when you throw a ball.
Unfortunately, I do not know how to incorporate these functions properly into my code?

Also, which line in the code is responsible for controlling the launch angle?

1 Like

(vx0 * t (vector x-speed doesn’t change so you can use speed*time), ay * t ^2 / 2 (ay - y-acceleration * t^2/2. It is from the function s = a * t^2 / 2, so you can turn it into y = acceleration * pow(t,2) / 2. Instad of pow(base,exponent) you can use t * t * t (=pow(t,3)))

so the function will be

x = startX + xSpeed * time;
y = startY + ySpeed * time (starting momentum calculation) + yAcceleration * time * time / 2;

Hope this helps

1 Like

Thank you very much.

Where do I write this in @r.jaoui’s code ? :slight_smile:

he is updating the position here:

speed.add(PVector.mult(new PVector(0, 60), dt));
pos.add(PVector.mult(speed, dt));
trace.add(pos.copy());

He didn’t use the code however, he did give you the formula
vector(t) = speed * time.

Thank you very much. I understand this know :slight_smile:

If I for example want to launch the ball with a start speed of 8 m/s with a launch angle of 40 degrees, how do I write this in the code?

1 Like

here is a simple program I wrote with your specifications (and btw you cannot use terms such as 8m/s, since scale is relative. Mesurements are pointless without scale. Try playing around with it a bit.

float sx = 100, sy = 500, xspeed, yspeed, xacc = 0, yacc = 0.5;
ArrayList<PVector> p = new ArrayList<PVector>();
int t = 0;
void setup() {
  size(600,600);
  float dir = -radians(40), speed = 20;
  xspeed = cos(dir)*speed;
  yspeed = sin(dir)*speed;
}
void draw() {
  fill(255);
  noStroke();
  background(0);
  float x = getPos(sx,xspeed,xacc,t), y = getPos(sy,yspeed,yacc,t);
  circle(x,y,5);
  if(mousePressed) {t++;p.add(new PVector(x,y));}
  noFill();
  stroke(255);
  beginShape();
  for(int i = 0; i < p.size(); i++) vertex(p.get(i).x,p.get(i).y);
  endShape();
  noFill();
  println(t,p.size());
}
float getPos(float start, float startSpeed, float acceleration, float time) {
  return( start + startSpeed * time + acceleration*time*time/2 );
}