• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by DayyanSisson · Dec 29, 2011 at 02:03 AM · guishootingcrosshairtargetingflight

Crosshair Targeting System

I'm making a space sim, and I need a targeting cursor in front of an enemy so the player can aim. Since when you fire a bullet, you need to fire ahead so the bullet actually hits it's target. It's hard at the moment to judge where to shoot based off your speed, the bullet's speed, and your distance from the target. So essentially there would be a little crosshair in front of the target where the player needs to shoot in order to hit it. Here's an example (What I'm talking about doesn't actually start till 2:35). I know I need to do some math to calculate where to place the GUI crosshair based off that target's distance, the target's speed, your speed, and the bullet's speed. I just don't know where to start. Any help would be appreciated.

Comment
Flickayy

People who like this

1 Show 0
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

  • Sort: 
avatar image

Answer by aldonaletto · Dec 30, 2011 at 03:04 AM

Actually, that game doesn't seem to do that - it seems to just draw a crosshair at some distance in the airplane's forward direction.
But if you want to find the position where to shoot taking into account the target velocity, there exists a "mathmagic" to do that: the function HitTime below calculates the time needed to a projectile with velocity speed to reach the target targ moving at velocity vel (if the target is moving away too fast to be reached, the function returns -1). Once the time is calculated, you can find the position to shoot using the target velocity, draw the crosshair and shoot in its direction.
In most cases you don't know the target velocity, but you can calculate it from the target positions over time. The calculated velocity is somewhat jerky, thus you must filter it in order to have a smooth behaviour - but this also makes the aim unreliable until the calculated velocity reaches a stable value.
You must fire the projectile by setting its rigidbody.velocity to bulletSpeed * direction.normalized (forget about AddForce - you will never get the correct speed).

// targ is the target transform, vel is its velocity vector, // and speed is the projectile speed. Returns the time needed // to reach the target, or -1 if it's not possible

function HitTime(targ: Transform, vel: Vector3, speed: float): float { var dist = targ.position - transform.position; var a = Vector3.Dot(vel, vel) - speed speed; var b = 2 Vector3.Dot(vel, dist); var c = Vector3.Dot(dist, dist); var det = b b - 4 a c; if (det >= 0) return 2 c / (Mathf.Sqrt(det) - b); else return -1; }

// that's an example code to test this function:

var guiCross: GUITexture; // drag the GUITexture crosshair here var target: Transform; // target transform var bulletSpeed: float = 10; // projectile speed

private var targetVel: Vector3; private var lastPos: Vector3;

function Update(){ if (target){ // if some target locked... // if you don't know the target velocity, calculate it var vel = (target.position - lastPos)/Time.deltaTime; lastPos = target.position; // filter the velocity to avoid a shaking crosshair targetVel = Vector3.Lerp(targetVel, vel, Time.deltaTime);

 // calculate the hit position:
 var t = HitTime(target, targetVel, bulletSpeed);
 if (t < 0){
   // target moving away too fast to be reached
   guiCross.enabled = false;
 } else {
   // target may be hit:
   guiCross.enabled = true;
   // calculate the position where the target will be hit
   var hitPos = target.position + t * targetVel;
   // calculate the crosshair position
   var crossPos = Camera.main.WorldToViewportPoint(hitPos);
   guiCross.transform.position = crossPos;
 }
 
 if (Input.GetButtonDown("Fire1")){
   var missile = GameObject.CreatePrimitive(PrimitiveType.Sphere);
   Destroy(missile, 20); // kill the missile after 20s
   missile.AddComponent(Rigidbody);
   missile.rigidbody.position = transform.position;
   missile.rigidbody.useGravity = false;
   
   // use this to shoot at the calculated point:
   var dir = hitPos - transform.position;
   missile.rigidbody.velocity = dir.normalized * bulletSpeed;
 }

} } CREDITS: I based the HitTime function in an interesting article about this subject, *Leading a target*.

Comment
Flickayy

People who like this

1 Show 0 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image

Answer by asafsitner · Dec 29, 2011 at 11:01 AM

Start with `Camera.WorldToScreenPoint();` Calculate the necessary targeting crosshair's position in 3D, then use the WorldToScreenPoint method to transfer it's position to a point on the screen.

How to calculate the crosshair's position, though?

Algorithm should be something like:

  1. Determine projectile's travel time from weapon position to enemy position through division of distance by speed and then again by average FPS

  2. Predict enemy's position by calculating it's position in the next frame, multiplied by the projectile's travel time (to predict rotation have a look at this answer - it's working great)

  3. Call Camera.WorldToScreenPoint(predictedPosition);

  4. Draw the crosshair through GUI

Comment

People who like this

0 Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image DayyanSisson · Dec 29, 2011 at 10:58 PM 0
Share

"Average FPS" being average frames-per-second or average feet-per-second (speed of bullet)? And also, how would I predict it's location in the next frame? Current location * speed / FPS?

avatar image DayyanSisson · Dec 29, 2011 at 11:47 PM 0
Share

And as for drawing the texture, how do I put it's position based off the predicted position, because I tried this :

 GUI.DrawTexture(new Rect(cursorScreenLocation), bulletTargetingCrosshair, ScaleMode.ScaleToFit, true, 10.0F);

And this :

 GUI.DrawTexture(cursorScreenLocation, bulletTargetingCrosshair, ScaleMode.ScaleToFit, true, 10.0F);

But I got errors both times.

avatar image JPB18 · Dec 30, 2011 at 01:20 AM 0
Share

Well, nighthawx349, you could use Pythagoras Theorem on that one. You would need the measure the distance between you and the target object, then calculate the travel time of the projectile, then multiply that value with the velocity of the target and there you would have the distance where you would need to place the "crosshair"... Something like this:

var TargetSpeed; var ProjSpeed; var TargetDist; var CrossDist;

CrossDist = (TargetDist/ProjSpeed) * TargetSpeed;

Hope I've helped =)

avatar image DayyanSisson · Dec 30, 2011 at 02:27 AM 0
Share

Well this is what I have here :

 //Component Check
         Combat other = plane.GetComponent<Combat>();
         PaperPlaneAI planeAI = target.GetComponent<PaperPlaneAI>();
         
         //Variable Check
         target = other.targetHit;
         targetSpeed = planeAI.speed;
         targetDistance = Vector3.Distance(target.transform.position, plane.position);
         Vector3 fwd = target.TransformDirection(Vector3.forward);
         
         //Next Steps
         bulletTravelTime = targetDistance/bulletVelocity;
         targetsNextLoc = fwd * targetSpeed/70;
         
         //Final Step
         cursorLocation = bulletTravelTime * targetsNextLoc;
         cursorScreenLocation = camera.WorldToScreenPoint(cursorLocation);
avatar image asafsitner · Dec 30, 2011 at 06:25 AM 0
Share

Average FPS as is Frames Per Second, as you're calculating positions from one frame to the next. It's basically Pythagoras's theorem, but the tricky part is predicting enemy's position. Luckily, a prediction solution already exists for networking lag compensation which you can probably dig and reuse (basically in both cases you're trying to extrapolate the Transform's movement).

A better example of what you're trying to achieve can be found in Black Prophecy

Unity Answers is in Read-Only mode

Unity Answers content will be migrated to a new Community platform and we are aiming to launch a public beta by June 9. Please note, Unity Answers is now in read-only so we can prepare for the final data migration.

For more information and updates, please read our full announcement thread in the Unity Forum.

Follow this Question

Answers Answers and Comments

7 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How can I match the score script to my fire script, on a per click basis 1 Answer

2d Sidescroller Crosshair! 1 Answer

Crosshair is not sticking with target position 0 Answers

Shooting Accuracy Problem 0 Answers

Flight HUD - flight angles 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges