Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • 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
0
Question by KnC_Studios · Aug 02, 2013 at 11:52 PM · javascriptfpsaienemyaiaccuracy

How do I make an enemy lead his shots?

Hi, I am making a fps from the fps tutorial and have come across a problem. My robots fire at you but you can easily doge by just moving slightly to the side or to keep moving. I want them to lead their shots so they will hit you where your going. Can anyone tell me what to change in my script? Thanks.

AI.js

 var attackRange = 30.0;
 var shootAngle = 4.0;
 var dontComeCloserRange = 5.0;
 var delayShootTime = 0.35;
 var pickNextWaypointDistance = 2.0;
 var target : Transform;
 
 private var lastShot = -10.0;
 
 // Make sure there is always a character controller
 @script RequireComponent (CharacterController)
 
 function Start () {
     // Auto setup player as target through tags
     if (target == null && GameObject.FindWithTag("Player"))
         target = GameObject.FindWithTag("Player").transform;
 
     Patrol();
 }
 
 function Patrol () {
     var curWayPoint = AutoWayPoint.FindClosest(transform.position);
     while (true) {
         var waypointPosition = curWayPoint.transform.position;
         // Are we close to a waypoint? -> pick the next one!
         if (Vector3.Distance(waypointPosition, transform.position) < pickNextWaypointDistance)
             curWayPoint = PickNextWaypoint (curWayPoint);
 
         // Attack the player and wait until
         // - player is killed
         // - player is out of sight        
         if (CanSeeTarget ())
             yield StartCoroutine("AttackPlayer");
         
         // Move towards our target
         MoveTowards(waypointPosition);
         
         yield;
     }
 }
 
 
 function CanSeeTarget () : boolean {
     if (Vector3.Distance(transform.position, target.position) > attackRange)
         return false;
         
     var hit : RaycastHit;
     if (Physics.Linecast (transform.position, target.position, hit))
         return hit.transform == target;
 
     return false;
 }
 
 function Shoot () {
     // Start shoot animation
     animation.CrossFade("shoot", 0.3);
 
     // Wait until half the animation has played
     yield WaitForSeconds(delayShootTime);
     
     // Fire gun
     BroadcastMessage("Fire");
     
     // Wait for the rest of the animation to finish
     yield WaitForSeconds(animation["shoot"].length - delayShootTime);
 }
 
 function AttackPlayer () {
     var lastVisiblePlayerPosition = target.position;
     while (true) {
         if (CanSeeTarget ()) {
             // Target is dead - stop hunting
             if (target == null)
                 return;
 
             // Target is too far away - give up    
             var distance = Vector3.Distance(transform.position, target.position);
             if (distance > shootRange * 3)
                 return;
             
             lastVisiblePlayerPosition = target.position;
             if (distance > dontComeCloserRange)
                 MoveTowards (lastVisiblePlayerPosition);
             else
                 RotateTowards(lastVisiblePlayerPosition);
 
             var forward = transform.TransformDirection(Vector3.forward);
             var targetDirection = lastVisiblePlayerPosition - transform.position;
             targetDirection.y = 0;
 
             var angle = Vector3.Angle(targetDirection, forward);
 
             // Start shooting if close and play is in sight
             if (distance < shootRange && angle < shootAngle)
                 yield StartCoroutine("Shoot");
         } else {
             yield StartCoroutine("SearchPlayer", lastVisiblePlayerPosition);
             // Player not visible anymore - stop attacking
             if (!CanSeeTarget ())
                 return;
         }
 
         yield;
     }
 }
 
 function SearchPlayer (position : Vector3) {
     // Run towards the player but after 3 seconds timeout and go back to Patroling
     var timeout = 3.0;
     while (timeout > 0.0) {
         MoveTowards(position);
 
         // We found the player
         if (CanSeeTarget ())
             return;
 
         timeout -= Time.deltaTime;
         yield;
     }
 }
 
 function RotateTowards (position : Vector3) {
     SendMessage("SetSpeed", 0.0);
     
     var direction = position - transform.position;
     direction.y = 0;
     if (direction.magnitude < 0.1)
         return;
     
     // Rotate towards the target
     transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
     transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
 }
 
 function MoveTowards (position : Vector3) {
     var direction = position - transform.position;
     direction.y = 0;
     if (direction.magnitude < 0.5) {
         SendMessage("SetSpeed", 0.0);
         return;
     }
     
     // Rotate towards the target
     transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
     transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
 
     // Modify speed so we slow down when we are not facing the target
     var forward = transform.TransformDirection(Vector3.forward);
     var speedModifier = Vector3.Dot(forward, direction.normalized);
     speedModifier = Mathf.Clamp01(speedModifier);
 
     // Move the character
     direction = forward * speed * speedModifier;
     GetComponent (CharacterController).SimpleMove(direction);
     
     SendMessage("SetSpeed", speed * speedModifier, SendMessageOptions.DontRequireReceiver);
 }
 
 function PickNextWaypoint (currentWaypoint : AutoWayPoint) {
     // We want to find the waypoint where the character has to turn the least
 
     // The direction in which we are walking
     var forward = transform.TransformDirection(Vector3.forward);
 
     // The closer two vectors, the larger the dot product will be.
     var best = currentWaypoint;
     var bestDot = -10.0;
     for (var cur : AutoWayPoint in currentWaypoint.connected) {
         var direction = Vector3.Normalize(cur.transform.position - transform.position);
         var dot = Vector3.Dot(direction, forward);
         if (dot > bestDot && cur != currentWaypoint) {
             bestDot = dot;
             best = cur;
         }
     }
     
     return best;
 }
Comment
Add comment · Show 4
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 robertbu · Aug 02, 2013 at 11:56 PM 0
Share

I don't see the code that aims and shoot the projectile here. In order to lead your character, you will need the velocity of the character. How you get that will depend on how the character is moved: CharacterController, Rigidbody, or Transform.

avatar image KnC_Studios · Aug 03, 2013 at 12:44 AM 0
Share

Sorry, here is the firing script.

 var projectile : Rigidbody;
 var initialSpeed = 20.0;
 var reloadTime = 0.5;
 var ammoCount = 20;
 private var lastShot = -10.0;
 
 function Fire () {
     // Did the time exceed the reload time?
     if (Time.time > reloadTime + lastShot && ammoCount > 0) {
         // create a new projectile, use the same position and rotation as the Launcher.
         var instantiatedProjectile : Rigidbody = Instantiate (projectile, transform.position, transform.rotation);
             
         // Give it an initial forward velocity. The direction is along the z-axis of the missile launcher's transform.
         instantiatedProjectile.velocity = transform.TransformDirection(Vector3 (0, 0, initialSpeed));
 
         // Ignore collisions between the missile and the character controller
         Physics.IgnoreCollision(instantiatedProjectile.collider, transform.root.collider);
         
         lastShot = Time.time;
         ammoCount--;
     }
 }
avatar image robertbu · Aug 03, 2013 at 12:56 AM 0
Share

Is this a 2D or 3D game? Does your character use a Character Controller or a Rigidbody to move?

avatar image KnC_Studios · Aug 03, 2013 at 01:05 AM 0
Share

$$anonymous$$y character uses a character controller. It is a 3d fps game. The movement script for the player is the standard Character $$anonymous$$otor. I also have a sprint and crouch script that shares with the Character $$anonymous$$otor.

Advanced $$anonymous$$otor Add-on.js

 var walkSpeed: float = 7; // regular speed
 var crchSpeed: float = 3; // crouching speed
 var runSpeed: float = 20; // run speed
  
 private var ch$$anonymous$$otor: Character$$anonymous$$otor;
 private var ch: CharacterController;
 private var tr: Transform;
 private var height: float; // initial height
  
 function Start(){
     ch$$anonymous$$otor = GetComponent(Character$$anonymous$$otor);
     tr = transform;
     ch = GetComponent(CharacterController);
     height = ch.height;
 }
  
 function Update(){
  
     var h = height;
     var speed = walkSpeed;
     
     if (ch.isGrounded && Input.Get$$anonymous$$ey("left shift") || Input.Get$$anonymous$$ey("right shift")){
         speed = runSpeed;
     }
     if (Input.Get$$anonymous$$ey("c")){ // press C to crouch
         h = 0.5 * height;
         speed = crchSpeed; // slow down when crouching
     }
     ch$$anonymous$$otor.movement.maxForwardSpeed = speed; // set max speed
     var lastHeight = ch.height; // crouch/stand up smoothly 
     ch.height = $$anonymous$$athf.Lerp(ch.height, h, 5*Time.deltaTime);
     tr.position.y += (ch.height-lastHeight)/2; // fix vertical position
 }

2 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by robertbu · Aug 03, 2013 at 02:01 AM

The basic idea is to get the velocity of the character and calculate the time of flight of the projectile to their current position. Using the flight time, you can make a rough projection about where the character will be by the time the missile arrives. You then aim at the new position. What I've done here is a bit simplified and imperfect, but you are not looking for perfect. And it is untested. It assumes the character is named "Player". Change as needed.

 #pragma strict
 var projectile : Rigidbody;
 var initialSpeed = 20.0;
 var reloadTime = 0.5;
 var ammoCount = 20;
 private var lastShot = -10.0;
 
 private var cc : CharacterController; 
 private var player : Transform;
 
 function Start() {
     var go = GameObject.Find("Player");
     player = go.transform;
     cc = go.GetComponent(CharacterController);
  }
 
  
 function Fire () {
     // Did the time exceed the reload time?
     if (Time.time > reloadTime + lastShot && ammoCount > 0) {
        // create a new projectile, use the same position and rotation as the Launcher.
        var instantiatedProjectile : Rigidbody = Instantiate (projectile, transform.position, transform.rotation);
        
        // Time of flight to reach player
        var t = (player.position - transform.position).magnitude / initialSpeed;
        
        // Project future position
        var futurePos = player.position + cc.velocity * t;
        
        // Aim and fire at that future position
         var aim = (futurePos - transform.position).normalized;
        instantiatedProjectile.transform.rotation = Quaternion.LookRotation(aim);
        instantiatedProjectile.velocity = aim * initialSpeed;
  
        // Ignore collisions between the missile and the character controller
        Physics.IgnoreCollision(instantiatedProjectile.collider, transform.root.collider);
  
        lastShot = Time.time;
        ammoCount--;
     }
 }
Comment
Add comment · Show 14 · 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 KnC_Studios · Aug 03, 2013 at 03:03 AM 0
Share

This is superb, except that the rocket mesh is now not facing forwards. It probably has to do with it not moving orthodoxly. Could you tell me how to make them point towards their current direction.

avatar image robertbu · Aug 03, 2013 at 03:06 AM 1
Share

I added line 32 in the script above to aim the projectile at the new position.

avatar image KnC_Studios · Aug 03, 2013 at 03:09 AM 0
Share

I, mean object, not mesh. The rocket object is facing the direction the robot is facing not were it's going. $$anonymous$$y apologies.

avatar image robertbu · Aug 03, 2013 at 03:42 PM 1
Share

Reading back through your comments, it is the missile/rocket that is not pointing in the correct direction or the launcher? The line of code I added should have fixed the problem:

  instantiatedProjectile.transform.rotation = Quaternion.LookRotation(aim);

This points the forward of the missile towards the new target.

avatar image robertbu · Aug 03, 2013 at 03:54 PM 1
Share

If you go back and take a look at my original answer, you will find the line already added. I edited the code right after you indicated you had a problem with the aim.

Show more comments
avatar image
1

Answer by Ian094 · Aug 03, 2013 at 01:05 AM

You can try using transform.LookAt heres an example:

 var Player : Transform;
 
 function Update(){
 transform.LookAt(Player);
 }

Just attach this to your AI and they might never miss again.

Comment
Add comment · Show 1 · 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 KnC_Studios · Aug 03, 2013 at 01:09 AM 0
Share

This is very useful, but I don't want to have a bunch of snipers with rocket launchers. I'll work on it. I kinda want the m to hit most of the time but when I sprint I want it to miss because i'm moving too fast. Thanks anyway.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

16 People are following this question.

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

Related Questions

How do you make a enemy AI hear approaching footsteps? 2 Answers

Character Animation won't work with FPS scripts 1 Answer

How to make enemy attack multiple unit rather then single?(updated) 1 Answer

Problem with the movement of AI 1 Answer

Make an enemy only rotate with navmesh agent 1 Answer


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