How to make enemy Cannonball fall on moving target position.

How do I make enemy cannon ball fall on target position?

My target (PLAYER) is moving and I would like the enemy turret (which catapults cannonball in arc) to be always able to hit target position - where it was recently standing when the cannon ball was catapulted.

So that if target would stand still the cannonball would actually land on target.

So far my cannon ball always lands in same distance from turret.

1 Answer

1

The easiest way to do that is to shoot always at a 45 degrees elevation, and adjust the velocity to reach the target distance (45 degrees gives the greatest range - read about it in the Temple of Wisdom, aka Wikipedia). If the target and the turret are at the same height, the initial cannon ball velocity is given by Mathf.Sqrt(distance * gravity).
The function BallisticVel in the script below returns the velocity necessary to hit the object defined by myTarget:

var myTarget: Transform;
var cannonball: GameObject;

function BallisticVel(target: Transform): Vector3 {

	var dir = target.position - transform.position; // get target direction
	var h = dir.y;  // get height difference
	dir.y = 0;  // retain only the horizontal direction
	var dist = dir.magnitude ;  // get horizontal distance
	dir.y = dist;  // set elevation to 45 degrees
	dist += h;  // correct for different heights
	var vel = Mathf.Sqrt(dist * Physics.gravity.magnitude);
	return vel * dir.normalized;  // returns Vector3 velocity
}

function Update(){

	if (Input.GetKeyDown("b")){
		var ball: GameObject = Instantiate(cannonball, transform.position, transform.rotation);
		ball.rigidbody.velocity = BallisticVel(myTarget);
		Destroy(ball, 10);
	}
}

To test this script, assign it to an empty object, drag the target to myTarget and your cannon ball prefab to cannonball, then press the key b to shot.

NOTE: Set the object position to a height that ensures the cannon ball will not touch any collider when instantiated, or this will alter the cannon ball movement and it will never reach the target. If you want to place the game object in your turret, set Is Trigger in the turret’s collider to avoid this interference.

EDITED: I modified the script a little to compensate for small differences in height between the turret and the target. The idea is: the cannon ball reaches the destination point at the same angle it was launched; since we are shooting at 45 degrees, any difference in height will produce a similar difference in the distance - at least near to the calculated impact point. In practical terms, if the target is 5 units above the turret, I can shoot to a point 5 units farther, and the cannon ball trajectory will pass through the actual player position. It’s a valid approximation for height differences about up to 20% of the horizontal distance, but the error may become excessive outside this range. There’s a complete equation in the reference I provided, but it seems impossible to solve with linear methods, so this approximation may be the best alternative.

I could be wrong but it looks like he is setting something once (a constant velocity). FixedUpdate should only be necessary if working with physics as a true update (every frame). In a real implementation you wouldn't want to use Update at all since it would run everyframe but only be needed on the more rare occasion "b" is pressed. You'd want some sort of input manager to send out events. If it is only one object its perfectly OK though. My point is, this isn't being used to actually update anything.

@Rafes is right: the rigidbody velocity is set only when you shoot, so it makes no difference where it is done - the new velocity will take effect only in the next physics cycle (which is in sync with FixedUpdate). You must use FixedUpdate to make regular changes - to move with Translate or to apply some constant or regularly variable force, for instance.

Try to position the turret at the same height as the player. The function BallisticVel assumes that the turret (spawn point) and the target are at the same height (same Y), but can correct for "small" differences (something like up to 20% of the horizontal distance). If the heights are different, a trajectory error will gradually appear as the target gets closer to the turret. If the target is lower than the turret, this error will produce NANs when the horizontal distance becomes lower than the height difference.

Hi pal! I'm looking for a way to archive the same but with variable angles (from 30 to 80 degrees) any suggestion? Thanks in advance!

Yes: a newer version of BallisticVel accepts variable angles, and can be found in my answer to this question: http://answers.unity3d.com/questions/148399/shooting-a-cannonball.html There's also a C# version of the variable angle BallisticVel in http://answers.unity3d.com/questions/235861/use-a-vector3-position-to-calculate-where-a-bomb-f.html