PDA

View Full Version : Simple(?) physics question


Jesse Aldridge
11-06-2006, 03:26 PM
I've been wrestling with this problem all day, and just can't quite seem to get it down:

How can I determine the initial velocity needed to make a projectile go from the origin to a specific point?

I'm talking 2D here. Like one of those simple artillery games.

TimS
11-06-2006, 04:45 PM
hrm...

I don't have a way to check this at hand so I can't see if or where it breaks, but try this (sorry for the clumsy formula formatting here):

Vo = sqrt( (Ag * (Px2 - Px1)^2) / ( ( (Px2 - Px1) * tan(theta) - (Py2 - Py1)) * 2 * (cos(theta))^2 ) )

where Vo is the original velocity (speed, really... not a vector), Ag is the acceleration due to gravity, the initial point is Px1 and Py1, the destination point is Px2 and Py2, and theta is the angle you're shooting at. And you're taking the square root of that whole mass of division there...

I'm assuming the angle is 'safe', too... so make sure you're shooting over those cliffs and not through 'em.

Let me know if this doesn't work or if you need me to clean up the formula so it's actually readable... :D

mmm physics.

-Tim

ggambett
11-06-2006, 04:57 PM
The x component is trivial because there's no acceleration so you have constant speed, so if you want the movement to take T seconds, the x speed is (X1 - X0)/T.

The y component is slightly more complex. I assume you have the initial and final height of the movement (ie the Y coordinates Y0 and Y1). If y(t) is the height at time T, you know that y(0) = Y0, and y(T) = Y1. y(t) is given by y(t) = Y0 + integral(0 to t)[ v(x)dx ], that is, the initial height plus how the speed v affected the height since the movement started. In a similar way v(t) = V0 + integral(0 to t)[ a(x)dx ]. V0 is what you want to find, the initial Y speed. Fortunately a(x) is a constant because it represents gravity, so the integral is a*t, therefore v(t) = V0 + a*t. Now the primitive of that needed for the integral in the y(t) formula is t*V0 + a*t*t/2 + K. We finally arrive at the known formula for parabollic movement y(t) = Y0 + V0*t + A*t*t/2 (the constants in the primitive cancel each other in the integral). You know Y0, you know A, and you know y(t) for t = T, so solving for V0 should be easy at that point.

TimS
11-06-2006, 05:09 PM
Who the hell could possibly read my first formula there...

here I typed it into Mathematica for pretty font action:

http://www.timscheiman.com/formula.JPG

-Tim

zppz
11-07-2006, 12:43 AM
Here is how the characters in my game determine how hard to throw something to make it land on a given point - aren't they clever?

//aimLocation is the desired landing point of the thrown object
//angle is the initial elevation of throw (typically between 0 and 90)
void GameObject::updateAimTrajectory(Vector& aimLocation, float aimAngle)
{
if (angle < -35 || angle > 85)
return;
Vector toTarget = aimLocation - location;
float horizDistToTarget = toTarget.horizontalDistance();
if (horizDistToTarget < 0.1f)
return;
float slopeToTarget = toTarget.y / horizDistToTarget;
//calculate throw direction vector
throwDir = toTarget;
throwDir.y = 0;
throwDir.normalise();
throwDir.y = tanf(aimAngle * DEGTORAD);
throwDir.normalise();
//throwDir is now a unit vector pointing in the launch direction

float maxThrowPowerForThisObject = maxThrowPower / this->heldObject.mass;

//where does line to target intersect parabola for max throw
float sinq = sinf(aimAngle * DEGTORAD);
float cosq = cosf(aimAngle * DEGTORAD);
float tanq = tanf(aimAngle * DEGTORAD);
float g = 9.81f;
float a = g / ( 2 * maxThrowPowerForThisObject * maxThrowPowerForThisObject * cosq * cosq);
float b = tanq - slopeToTarget;
float intersectRange = b / a;
float normalRange = 2/g * maxThrowPowerForThisObject * maxThrowPowerForThisObject * sinq * cosq;//this is how far it would get if thrown at maxThrowPowerForThisObject
float fractionOfNormalRange = intersectRange / normalRange;

//find necessary normal range to put projectile at fraction position at correct time
float necessaryRange = 1.0f / fractionOfNormalRange * horizDistToTarget;

//find power necessary to throw to necessaryRange
throwPower = sqrtf((g*necessaryRange) / (2*sinq*cosq));

if (throwPower > maxThrowPowerForThisObject) {
throwPower = maxThrowPowerForThisObject;
throwAchievable = false;
}
else
throwAchievable = true;
}

This is for 3D but should be fine for 2D as well. I did not bother to check if it is the same as Tim's formula but it works for me so... hope it helps.
Bear in mind this is a class function and the purpose of it is to update the class variables throwDir, throwPower, and throwAchievable. location is also a class variable. 'power' should probably be 'force'

Jesse Aldridge
11-07-2006, 11:09 AM
Thanks guys. I got it working.