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 velocity;//m/s
static final float RATIO=4;//10px=1m
Ball ball1;
static final float G=9.81;
PVector velocity;//m/s
static final float RATIO=4;//10px=1m
Ball ball1;
static final float G=9.81;
The ball object is declared as well as the speed of the ball as an object of class PVector. Also the variable frameRate whose value is set to 20 frames per second, as well as the constant G which represents the value of the gravitational acceleration.
In the setup method, an object of the Ball class is defined and the ball speed attribute(ball.v) is set to the value of the speed, which is also defined in the setup method, and actually represents the ball's initial speed vector. If this value is set to (0,0) then we will get a free fall of the ball. So, the setup method is defined as follows:
In the setup method, an object of the Ball class is defined and the ball speed attribute(ball.v) is set to the value of the speed, which is also defined in the setup method, and actually represents the ball's initial speed vector. If this value is set to (0,0) then we will get a free fall of the ball. So, the setup method is defined as follows:
void setup()
{
{
size(1000,600);//100m * 60m in the nature
velocity=new PVector(0,0);
ball1= new Ball(25,30,height/4);
ball1.v=brzina;
frameRate(frameRate);
}velocity=new PVector(0,0);
ball1= new Ball(25,30,height/4);
ball1.v=brzina;
frameRate(frameRate);
The frame size is set to 1000 * 600px. A ball with a radius of 25px is placed at an initial position of 30px along the x-axis and at 1/4 height from the ground (height - (1/4)*height).
Within the draw method, the background color, outline color and fill of the ball are defined. The methods defined previously in the ball class are also called: move(), boundaryConditions() and render().
The full sketch can be seen in the image below:
Within the draw method, the background color, outline color and fill of the ball are defined. The methods defined previously in the ball class are also called: move(), boundaryConditions() and render().
The full sketch can be seen in the image below:
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: