First, you should probably set it so that the tank doesn't collide with its own projectiles. Even if you have the right impulse to fire the sphere directly at the enemy, it could hit the insides of your tank and stop
You can do this by changing the collision rule between the projectile and the tank:
Code: Select all
tank.collisionRules.specificEntities.Add(projectile, CollisionRule.noPair);
To prevent tons of extra worthless collision rules piling up in the list after the projectiles are gone, it would be a good idea to remove the projectiles from the tank's collision rules when they 'explode' later on.
For simplicity, I'm going to use the entity's linearVelocity field as opposed to the apply impulse method. Internally, the linear velocity property computes the appropriate impulse for you, so all you need to worry about is finding what the initial velocity needs to be.
There's more than one way of going about calculating the velocity depending on what kind of behavior you're looking for. So I'm going to say arbitrarily that the horizontal speed of this projectile, traveling through the X-Z plane, is going to be some value I'll call horizontalSpeed (which you can define). Now that that is fixed, we only need to figure out what the vertical velocity needs to be to reach the target.
To get started on that, we need the time it will take for the projectile to make it to the target based on its horizontal speed. Time is the distance divided by the speed of the projectile.
Code: Select all
Vector2 horizontalDisplacement = new Vector2(targetPosition.X - position.X, targetPosition.Z - position.Z);
float horizontalDistance = horizontalDisplacement.Length();
float time = horizontalDistance / horizontalSpeed;
If there was no vertical displacement between the target and myself, the computation would now be straightforward as all that is needed is an application of kinematic equations (
http://www.physicsclassroom.com/class/1DKin/u1l6a.cfm). What is the upwards pointing velocity that causes the ball to take exactly 'time' seconds to return to the ground? Using the equation d = Vi * t + (1/2) * a * t^2 and solving for Vi (initial velocity):
0 = Vi * time + (1/2) * (gravity) * time^2
-Vi * time = (1/2) * (gravity) * time^2
-Vi = (1/2) * gravity * time (note that the root at zero was removed here by dividing by time, but we didn't care about it anyway)
Vi = -(1/2) * gravity * time
Plug in your values for gravity (as a scalar like -9.81 since its just pointing straight down) and time (computed earlier from horizontal distance), and there's your initial velocity.
For an environment where the tanks can be in different vertical positions, we still use the same basic approach but the end result is a tiny bit more complicated. d is vertical displacement, which was 0 before. Now, consider it to be targetPosition.Y - position.Y.
targetPosition.Y - position.Y = Vi * time + (1/2) * (gravity) * time^2
-Vi * time = -(targetPosition.Y - position.Y) + (1/2) * (gravity) * time^2
-Vi = -(targetPosition.Y - position.Y) / time + (1/2) * (gravity) * time
Vi = (targetPosition.Y - position.Y) / time - (1/2) * (gravity) * time
And there we go! This equation is equivalent to the last one where the displacement is zero (that term just drops out). Just plug in the numbers and it should work.
The initial 3d velocity is then computed as follows:
Code: Select all
Vector2 horizontalDirection = horizontalDisplacement / horizontalDistance;
Vector3 initialVelocity = new Vector3(horizontalDirection.X * horizontalSpeed, Vi, horizontalDirection.Y * horizontalSpeed);
Let me know if I messed up somewhere!