- Home /
How to get turrets to lead enemies : Topdown 2d
Hello,
Thanks for reading. I'm Having some difficulty figuring out the code to have turrets lead their targets. My old code just had the turrets tracking the enemies, so when they fired, they were less likely to hit fast moving enemies.
What I'm stuck on at the minute is figuring out what direction the target is moving, and how fast. (Line 10 of first code block)
Here's what I've got so far
// Get the distance to the enemy
float distanceToEnemy = Vector3.Distance(targetPosition, transform.position);
Debug.Log ("TurretGunScript.RotateTurret: Distance to enemy : " + distanceToEnemy);
// Get the amount of time it will take for bullet to hit enemy
float timeToHit = distanceToEnemy/bulletSpeed;
Debug.Log ("TurretGunScript.RotateTurret: Bullet travel time : " + timeToHit);
// Get the movement vector of enemy ??
// Multiply movement vector by time to hit to get the direction the turret should be facing
// Rotate turret to face that position
Quaternion neededRotation = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Slerp(transform.rotation, neededRotation, rotationSpeed * Time.deltaTime);
This is how the targets move:
rigidbody.AddForce (targetDirection.normalized * moveSpeed * Time.deltaTime);
transform.position = new Vector3(transform.position.x, 0, transform.position.z);
This is how bullets move:
transform.Translate(0, 0, moveSpeed * Time.deltaTime);
transform.position = new Vector3(transform.position.x, 0 , transform.position.z);
Thanks in advance!
Answer by Owen-Reynolds · Feb 28, 2013 at 04:57 PM
Basic idea is to see what direction/speed the target is moving, guess how many seconds it will take to hit, then use seconds*movement to estimate where the target will be:
float secsFlightTime = (target.position - turret.position).magnitude / bulletSpeed;
Vector3 targetMvPerSec = target.rigidbody.velocity; // since you physics to move
targetMovePerSec.y=0; // since your code says they stay flat
Vector3 estHitPos = target.position + targetMovePerSec*secsFlightTime;
The math will be wrong for two reasons. One is you can't know the actual flight seconds to where you'll hit without already knowing where you'll hit. So you just estimate based on current position. For faraway slow things, it works great. Otherwise, looping 2 or 3 times gets you really close (use estHitPos to re-figure flightTime and get a new estHitPos... .)
The other is your objects are constantly accelerating (AddForce.) If friction or something causes them to have a mostly constant speed, it should be OK.
Thanks Owen. The code works well. I managed to figure out a cludge solution, but had to multiply a variable by 1.5 to get the correct lead amount. I wouldn't $$anonymous$$d trying to understand why, so if you feel like looking at it, please let me know : ) Thanks again!
This is the value I had to multiply:
Vector3 targetVelocity = (target.rigidbody.velocity * timeToHit) * 1.5f; // This compensates for some descrepancy, presumably in bulletSpeed
This is the complete code:
// Get the distance to the enemy
float distanceToEnemy = Vector3.Distance(targetPosition, transform.position);
Debug.Log ("TurretGunScript.RotateTurret: Distance to enemy : " + distanceToEnemy);
// Get the amount of time it will take for bullet to hit enemy
float timeToHit = distanceToEnemy/bulletSpeed;
Debug.Log ("TurretGunScript.RotateTurret: Bullet travel time : " + timeToHit);
// Get the velocity of the target rigidbody and multiply by amount of time to hit
Vector3 targetVelocity = (target.rigidbody.velocity * timeToHit) * 1.5f; // This compensates for some descrepancy, presumably in bulletSpeed
// Add the velocity * time to the target's curret position
Vector3 finalPos = targetPosition + targetVelocity;
// Get the direction to aim the turret
Vector3 aimDirection = finalPos - bulletSpawn0.transform.position;
// Rotate turret to face that position
Quaternion neededRotation = Quaternion.LookRotation(aimDirection);
transform.rotation = Quaternion.Slerp(transform.rotation, neededRotation, rotationSpeed * Time.deltaTime);
The target's velocity is probably bobbing up and down each frame (AddForce, then friction or drag in the physics step.) Your code is probably running 1st, before the AddForce script, getting a "too low" velocity (but running after might give a "too high.")
For real, the velocity is currentPos-pos1SecondAgo. But that's a pain to remember. If you're a space rock, rigidbody.velocity
is your real speed. Otherwise it's just an estimate (this trick fires way to high if someone has just jumped.)
Your answer
Follow this Question
Related Questions
flip scale of a tank but turret aim wrong 0 Answers
2D Animation does not start 1 Answer
2d turret problem 1 Answer
Turret bullet rotation problem 1 Answer