Friday, March 16, 2018

java - How to create a projectile motion of a cannonball in top down view?


Objective



  • To move the bullet with projectile motion to specific destination by touch point.


In the below image is an example of a bullet which has a projectile motion. On my observation, the bullet speed and angle is calculated base on distance.



enter image description here
(source: pixwerk.net)


Where I'm at? (How do I move the bullet to its destination?)


In the below code, is the method I use to move a bullet to its destination. But the problem is I want to create a cannonball bullet which it has a projectile motion. How do I create these tricks to make a cannon ball projectile motion like the image below.


public Vector2 getVelocity(Vector2 currentPosition, Vector2 targetPosition) {
Vector2 targetDirection = targetPosition.cpy().sub(currentPosition);
return targetDirection
.nor();
}


What I have done? (Currently I could move the bullet straight to its destination.)



  • Bullet is moving straight (It's not problem).


enter image description here


[EDIT]


Drawing a projected trajectory


To get the trajectory point, base on iforced example. I've already have the libgdx box2d version of this.


b2Vec2 getTrajectoryPoint( b2Vec2& startingPosition, b2Vec2& startingVelocity, float n )
{

//velocity and gravity are given per second but we want time step values here
float t = 1 / 60.0f; // seconds per time step (at 60fps)
b2Vec2 stepVelocity = t * startingVelocity; // m/s
b2Vec2 stepGravity = t * t * m_world->GetGravity(); // m/s/s

return startingPosition + n * stepVelocity + 0.5f * (n*n+n) * stepGravity;
}

Rendering the trajectory point


glColor3f(1,1,0);

glBegin(GL_LINES);
for (int i = 0; i < 180; i++) { // three seconds at 60fps
b2Vec2 trajectoryPosition = getTrajectoryPoint( startingPosition, startingVelocity, i );
glVertex2f(trajectoryPosition.x, trajectoryPosition.y );
}
glEnd();

[Solve]


The answer is to find the angle and speed by the distance by s.tarik.cetin


Another issue encountered (this must be move to another question)



This is the problem, I don't know how do I set the starting velocity. Currently in the below code, to set the startingVelocity and startingPosition where the underlined code is the part that I'm not sure.


    touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPoint);

Vector2 touch = new Vector2(touchPoint.x, touchPoint.y);
Vector2 touchDirection = touch.cpy().sub(bulletPosition).nor(); // get the the direction from bullet position to touch point and normalize the value.

float distance = touchDirection.dst(startingPosition);
float angle = touch.angle();
float speed = 6.0f; // currently the speed is fixed. I need to know the speed base on distance


startingPosition.set(bulletPosition); // current position of the bullet
startingVelocity.set(touchDirection.scl(speed)); // where the bullet should be

Answer



From wikipedia:


$$d=\frac{v_0^2}{g}sin(2\theta)$$


When you reverse the formula to find the angle from the distance and initial speed, it becomes:


$$\eqalign{ d&=\frac{v_0^2}{g}sin(2\theta) \\ sin(2\theta)&=\frac{dg}{v_0^2} \\ arcsin(sin(2\theta))&=arcsin(\frac{dg}{v_0^2}) \\ 2\theta&=arcsin(\frac{dg}{v_0^2}) \\ \theta&=(arcsin(\frac{dg}{v_0^2}))/2 \\ }$$


So you can define this method:


double gravity; //Assuming you preset this.


double GetLaunchAngle (double distance, double initialSpeed)
{
double sineValue = distance * gravity / Math.Pow(initialSpeed, 2);

if(sineValue < -1 || sineValue > 1)
{
throw new Exception("There is no possible way of reaching the given distance with given initial speed.");
}


return Math.Asin(sineValue) /2;
}

Now, you can use the launch angle to launch your projectile, so it would draw a parabola in the air, just like the image you posted.


For the explanation of why we have an exception in method, check this section of the wikipedia article about projectile movement.




Edit:
If the intial velocity is not an essential part of your game, we can eliminate the exception by letting the game decide a suitable speed by fixing the launch angle:


double gravity; //Assuming you preset this.
double fixedLaunchAngle = 45; //This can be any angle, but you get the most distance with least speed if your launch angle is 45 degrees.


double GetInitialSpeed (double distance)
{
double sine = Math.Sin(2 * fixedLaunchAngle); //You can cache or even hardcode this value to avoid calculating over and over again.
double squaredSpeed = distance * gravity / sine;
return Math.Sqrt(squaredSpeed);
}

And here is a more generic version that allows you to also specify the launch angle:


double gravity; //Assuming you preset this.


double GetInitialSpeed (double distance, double launchAngle)
{
double sine = Math.Sin(2 * launchAngle); //You can *not* cache this, since it is a parameter now.
double squaredSpeed = distance * gravity / sine;
return Math.Sqrt(squaredSpeed);
}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...