CREATING AN ANIMATION OF A PROJECTILE MOTION USING JAVA AND PROCESSING
In the previous articles, the animation of the movement of the ball in the horizontal plane was shown, but the ball moved only in a straight line, changing the x and y coordinates. In the following, it will be described how gravity can be introduced, as a PVector object, which affects the movement of the ball, so that its movement corresponds to the situation in nature. In this way, the ball (circle) can describe the trajectory of a free fall, horizontal, vertical or oblique shot. In the following examples, it must be taken into account that the coordinate system for drawing shapes is not exactly as in nature with the Y axis pointing up, but the positive direction of the Y axis is down. Because of this, the direction of the gravity vector will be considered to be the opposite direction, so it will be multiplied by (-1). Another thing to consider is that the boundaries that the animation shows as a state of nature will not be displayed in meters but in pixels and that the width and height values of the frame in which the animation takes place will not be those of "nature", so you need to introduce scale. For example. if you want to show an animation that would naturally be 10m wide, and the width of the frame is e.g. 400px, then a scale of 40(px/m) should be entered.
Free fall animation in processing
We will continue creating the animation from the "HorizontalMovingBall" example done previously (see the Basics of Processing with Java page); The animation should look like the one below:
We will slightly modify the Ball class by introducing vectors (PVector) for acceleration and velocity, and replacing the existing coordinates xC, yC also with a vector that points to the center of the ball and represents its position in the XOY plane.
float r;//geometric koo
PVector position;
PVector v;
PVector g;
PVector position;
PVector v;
PVector g;
A variable representing the radius of the ball in px was also introduced.
The constructor of the Ball class receives as parameters the values of the radius of the ball as well as the x and y coordinates of the center of the ball. Inside the constructor, a ball position vector is created based on those coordinates and the value of the r attribute is initialized:
The constructor of the Ball class receives as parameters the values of the radius of the ball as well as the x and y coordinates of the center of the ball. Inside the constructor, a ball position vector is created based on those coordinates and the value of the r attribute is initialized:
public Ball(float r, float x, float y)
{
{
this.r=r;
position = new PVector(x,y);
g=new PVector(0,G);
}position = new PVector(x,y);
g=new PVector(0,G);
The gravitational acceleration vector g should have a y component defined as G=9.81 with a minus sign, but due to the turned coordinate system (positive y is downward) it has a positive value, which was already mentioned at the beginning of the page. The constant G will be defined inside the main sketch as a global variable.
The movement method will also be modified so that it now takes into account the effect of acceleration:
The movement method will also be modified so that it now takes into account the effect of acceleration:
public void move()
{
{
PVector a=PVector.div(g,frameRate);
v.add(a);
PVector dv=PVector.mult(v,SCALE);
position.add(dv);
}v.add(a);
PVector dv=PVector.mult(v,SCALE);
position.add(dv);
First, the acceleration vector is created by dividing the gravitational acceleration vector by the number of draw method calls per second, i.e. with the frameRate variable. the div method of the PVector class is used to keep the vector g original (read more about vectors in the article Vectors in Processing).
The impact of the acceleration was achieved by vectorial addition of the same to the velocity vector v, but previously the acceleration vector was multiplied scalar by the scale (described at the beginning of the article) using the mult method of the PVector class.
Both frameRate and SCALE variables are defined in the main sketch as global, so they are also available inside this class.
The impact of the acceleration was achieved by vectorial addition of the same to the velocity vector v, but previously the acceleration vector was multiplied scalar by the scale (described at the beginning of the article) using the mult method of the PVector class.
Both frameRate and SCALE variables are defined in the main sketch as global, so they are also available inside this class.
Drawing the ball that was previously in the draw method of the main sketch is transferred to the render method:
public void render()
{
{
fill(255,0,0);
ellipseMode(CENTER);
ellipse(position.x,position.y,2*r,2*r);
}ellipseMode(CENTER);
ellipse(position.x,position.y,2*r,2*r);
Here it can be observed that the color of the ball will be red, that the mode for drawing the ellipse (circle) is such that the coordinates in the call to the method that draws the circle (ellipse) represent the center of the circle. It should also be noted that now PVector object(position) is used for position coordinates.
The method that checks the boundary conditions has also been changed so that it now uses the introduced velocity and position vectors:
public void boundaryConditions()
{
{
if(v.y>0 && height-position.y < r){
/*Condition for the body to stop*/
if(abs(v.y) < 0.3 && height-position.y-r < -5)
{
}
v.y *= -0.8;//loss of energy
}/*Condition for the body to stop*/
if(abs(v.y) < 0.3 && height-position.y-r < -5)
{
noLoop();
}The first condition that is checked is whether the ball has reached the ground, and if so, the direction of the speed should be changed and the intensity somewhat reduced (multiplied by 0.8) due to energy losses when hitting the ground. The value 0.8 is taken arbitrarily. An additional condition checks if the direction of the velocity is downward, because upon impact the direction changes upward, and it may happen that in the first subsequent iteration the height value is still negative. This would undesirably change the direction of the ball again before it is at a positive height, which in the animation would look like "trapping" the ball on the ground.
The second if statement serves to stop the bounce animation when the bounce speed becomes "low" enough.
The complete Ball class now looks like this:
The second if statement serves to stop the bounce animation when the bounce speed becomes "low" enough.
The complete Ball class now looks like this:
Variables and constants that are available in other classes are defined in the main sketch at the beginning:
int frameRate=20;
PVector brzina;//m/s
static final float RAZMERA=4;//10px=1m
Lopta lopta1;
static final float G=9.81;
PVector brzina;//m/s
static final float RAZMERA=4;//10px=1m
Lopta lopta1;
static final float G=9.81;
Deklarisan je objekat lopte kao i brzina lopte kao objekat klase PVector. Takođe i promenljiva frameRate čija je vrednost postavljena na 20 frejmova u sekundi, kao i konstanta G koja predstavlja vrednost gravitacionog ubrzanja.
U setup metodi definiše se objekat klase Lopta i postavi se atribut brzine lopte na vrednost brzine koja se definiše takođe u setup metodi, a predstavlja zapravo vektor početne brzine lopte. Ukoliko se ova vrednost postavi na (0,0) onda ćemo dobiti slobodan pad lopte. Dakle, setup metoda je definisana na sledeći način:
U setup metodi definiše se objekat klase Lopta i postavi se atribut brzine lopte na vrednost brzine koja se definiše takođe u setup metodi, a predstavlja zapravo vektor početne brzine lopte. Ukoliko se ova vrednost postavi na (0,0) onda ćemo dobiti slobodan pad lopte. Dakle, setup metoda je definisana na sledeći način:
void setup()
{
{
size(1000,600);//100m * 60m u prirodi
brzina=new PVector(0,0);
lopta1= new Lopta(25,30,height/4);
lopta1.v=brzina;
frameRate(frameRate);
}brzina=new PVector(0,0);
lopta1= new Lopta(25,30,height/4);
lopta1.v=brzina;
frameRate(frameRate);
Veličina okvira je postavljena na 1000 * 600px. Lopta čiji je poluprečnik 25px je postavljena u početni položaj 30px po x osi i na 1/4 visine od tla(height - (1/4)*height).
Unutar draw metode se definišu boja pozadine, boja konture i ispune lopte. Takođe se pozivaju metode definisane prethodno u klasi lopta: kretanje(), granicniUslovi() i render().
Kompletan skeč se može videti na slici ispod:
Unutar draw metode se definišu boja pozadine, boja konture i ispune lopte. Takođe se pozivaju metode definisane prethodno u klasi lopta: kretanje(), granicniUslovi() i render().
Kompletan skeč se može videti na slici ispod:
Horizontal shot - animation in processing
To make a horizontal shot animation from the previously created animation, we'll add an x component to the initial velocity and add a boundary condition that checks if the ball hit the left or right wall, and if so, make it bounce off them by changing the direction velocities in the x direction. The creation of the initial velocity vector is in the setup method (colored red).
void setup()
{
{
size(1000,600);//100m * 60m in the nature
velocity=new PVector(5,0);
ball1= new Ball(25,30,height/4);
ball1.v=velocity;
frameRate(frameRate);
}velocity=new PVector(5,0);
ball1= new Ball(25,30,height/4);
ball1.v=velocity;
frameRate(frameRate);
It should also be added inside the Ball class, and in the boundaryConditions() method, testing the conditions for hitting the left or right wall:
public void boundaryConditions()
{
{
if(v.x > 0 && width-position.x < r || v.x < 0 && position.x < 0)
{
if(v.y>0 && height-position.y < r){
/*Condition for the body to stop*/
if(abs(v.y) < 0.3 && height-position.y-r < -5)
{
}{
v.x *= -0.8; //change of direction and loss of energy
}if(v.y>0 && height-position.y < r){
v.y *= -0.8;//loss of energy
}/*Condition for the body to stop*/
if(abs(v.y) < 0.3 && height-position.y-r < -5)
{
noLoop();
}The horizontal shot animation will look like this:
Projectile movement - animation in processing
From the previous horizontal shot animation, with small changes, we will get an oblique shot animation. First, inside the setup method, we will add, in addition to the initial velocity component in the x direction and a component in the y direction. We will also lower the starting height of the ball:
void setup()
{
{
size(1000,600);//100m * 60m in the nature
velocity=new PVector(5,-8);
ball1= new Ball(25,30,3*height/4);
ball1.v=velocity;
frameRate(frameRate);
}velocity=new PVector(5,-8);
ball1= new Ball(25,30,3*height/4);
ball1.v=velocity;
frameRate(frameRate);
After these changes, the cross-shot animation would look like this: