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 Hamesh81 · Mar 05, 2012 at 08:28 AM · raycastrotateobstacleavoidance

"Look at" logic interfering with simple raycast obstacle avoidance

I'm adding simple obstacle avoidance to a test AI script.

I have the default Unity cube with an added rigidbody which has my FPS controller's transform targeted. At a certain distance the cube first looks at (rotates towards) and then starts moving towards the player (FPS) via vector 3. Here is the (C#) script, anyone feel free to use this script for your own purposes:

 using UnityEngine;
 using System.Collections;
 
 public class EnemyAI3 : MonoBehaviour {
     public Transform target;
     public Transform idleStandPosition;
     public Transform idleLookDirection;
     public int idleStandDistance = 1;
     public int moveSpeed;
     public int rotationSpeed;
     public int maxDistance;
     
     public float attackTimer;
     public float coolDown;
     
     public float rayAttackTimer;
     public float rayCoolDown;
     public float raycastLength = 1f;
     
     public float seeDistance = 10f;
     public float startPursuitDistance = 5f;
     
     public bool raycastHitting = false;
     public bool idle = false;
     public bool canSeeTarget = false;
     public bool pursuing = false;
     public bool attacking = false;
     public bool retreating = false;
     
     public float turnSpeed = 5;
     
     private Transform myTransform;
     
     void Awake() {
         myTransform = transform;
     }
 
     // Use this for initialization
     void Start () {
         GameObject go = GameObject.FindGameObjectWithTag("Player");
         
         target = go.transform;
         
         maxDistance = 2;    
         attackTimer = 0;
         coolDown = 2.0f;
         
         rayAttackTimer = 0;
         rayCoolDown = 2.0f;
     }
     
     // Update is called once per frame
     void FixedUpdate () {
         
         if(attackTimer > 0)
             attackTimer -= Time.deltaTime;
         
         if(attackTimer < 0)
             attackTimer = 0;
         
         if(rayAttackTimer > 0)
             rayAttackTimer -= Time.deltaTime;
         
         if(rayAttackTimer < 0)
             rayAttackTimer = 0;
         
         Debug.DrawLine(target.position, myTransform.position, Color.yellow);
         //If the player is close enough for us to see it & our raycast is not hitting
         if(Vector3.Distance(target.position, myTransform.position) < seeDistance && !raycastHitting) {
             //Look at our target
             myTransform.rotation = Quaternion.Slerp(myTransform.rotation, Quaternion.LookRotation(target.position - myTransform.position), rotationSpeed * Time.deltaTime);
             canSeeTarget = true;
         }
         
         //If the player is too far for us to see it 
         if(Vector3.Distance(target.position, myTransform.position) < seeDistance && canSeeTarget)  {
             //Wait until our timer counts down
             attackTimer = coolDown;
             
         }
         //If the player is too far for us to see it & our timer has count down & our raycast is not hitting
         if(Vector3.Distance(target.position, myTransform.position) > seeDistance && attackTimer == 0 && !raycastHitting)  {
             //Look at our Idle Stand Position
             myTransform.rotation = Quaternion.Slerp(myTransform.rotation, Quaternion.LookRotation(idleStandPosition.position - myTransform.position), rotationSpeed * Time.deltaTime);
             canSeeTarget = false;
             //If we haven't reached our Idle Stand Position
             if(Vector3.Distance(idleStandPosition.position, myTransform.position)  > idleStandDistance) {
                 //Move towards our Idle Stand Position
                 myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime;
             }
             //If we have reached close to our Idle Stand Position & our raycast is not hitting
             if(Vector3.Distance(idleStandPosition.position, myTransform.position)  < idleStandDistance && !raycastHitting) {
                 //Look at our Idle Look Direction
                 myTransform.rotation = Quaternion.Slerp(myTransform.rotation, Quaternion.LookRotation(idleLookDirection.position - myTransform.position), rotationSpeed * Time.deltaTime);
             }
         }
         
         //If we haven't reached our Maximum Distance
         if(Vector3.Distance(target.position, myTransform.position) > maxDistance) {
             //If our target is close enough for us to start pursuit 
             if(Vector3.Distance(target.position, myTransform.position) < startPursuitDistance) {
                     
                 //Move towards player
                 myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime;
                 //pursuing = true;
             }
         }
         //Start Raycast
         if(Physics.Raycast(myTransform.position, myTransform.forward, raycastLength)){
             Debug.DrawLine(myTransform.position, myTransform.forward, Color.blue);
             myTransform.Rotate(Vector3.up, 90 * turnSpeed * Time.smoothDeltaTime);
             raycastHitting = true;
             rayAttackTimer = rayCoolDown;
         }
         if(!Physics.Raycast(myTransform.position, myTransform.forward, raycastLength) && rayAttackTimer == 0){
         raycastHitting = false;    
     }
         //End Raycast
     }
 }

I've added a raycast which when hit I would like to stop the "look at" and rotate the cube 90 degrees on the y axis. I'm not getting any errors, but at the moment it looks like the "look at" logic is stopping the raycast rotation function from happening since it is always trying to rotate towards the player. I've gone through several versions of this but can't seem to isolate the look at and raycast rotate to work separately. I'm sure it's something simple.

I've uploaded a package of the simple scene here. 3.6MB

Any ideas?

Comment
Add comment
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

1 Reply

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

Answer by Owen-Reynolds · Mar 05, 2012 at 06:42 PM

Might be helpful to chart out just what you want to happen. Often the program was perfect, but your idea was wrong, but:

An if/else decides what to do every frame, with no "memory" of last frame. So, your guy could not be blocked, rotate on Y for two frames, then the raycast hits a tree and it starts to spin back towards the player again, but then next frame is unblocked so rotates on Y again. Sometimes you want that, so nothing wrong with just ifs.

If you want it to "remember" something, such as "now I should spin for 1/2 second," you a var to remember it with. A common trick for something timed looks like:

 float doThingAUntilNow = 0.0f; // seconds
 // not an offset -- real time:
 // Ex:  time is 6, doThingA is 8 -> do A for 2 seconds (until time 8)
 // NOTE: if dTAUN is less than current time, we aren't doing A

 if( something happens) doThingAUntilNow = Time.time + howLongToDoIt;

 if(Time.time < doThingAUntilNow) doThingA();
 // optional:
 else {
   do whatever we'd do if not thing A
 }
Comment
Add comment · Show 9 · 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 Hamesh81 · Mar 05, 2012 at 09:21 PM 0
Share

Thanks for the really helpful advice Owen. Basically, I want for the AI to only "look at" its target when the raycast isn't hitting anything, as otherwise the raycast logic is telling the gameobject to turn 90 degrees and at the same time, the look at logic is trying to rotate it back to face the target. Would it be easiest to just set a boolean (eg. raycastIsHitting) to true whenever a raycast is hitting and then for the "look at" only activate it when the boolean is false? Something like this:

if(!raycastIsHitting) {

//Do the "look at" logic here

}

avatar image Owen-Reynolds · Mar 06, 2012 at 04:26 AM 0
Share

Suppose you have a thin tree between you and the target. Your idea will have the object look at the target, but then, since it's blocked by that tree, rotate away, then be unblocked and rotate back...

It will twitch just on the edge of the tree. Is that what you want?

avatar image Hamesh81 · Mar 06, 2012 at 07:46 AM 0
Share

Aah, I see what you're saying. Yes obviously twitching isn't very desirable haha, thanks for that. What if I put a timer on the cube so that after each raycast hit it would delay the rotation for looking back at the target. Since the cube is constantly moving forward (whether "looking at" or hitting via raycast) the brief rotation away and back at the target should be enough to let it navigate around, shouldn't it? I will be testing this later this afternoon, so atm it is just a theory :) What do you think?

avatar image Owen-Reynolds · Mar 06, 2012 at 02:08 PM 0
Share

doThingAUntilNow is a timer / stateVariable.

In practice, hard to say what will look right. Sometimes a "wider" or longer raycast; or less frequent; or a "turn for 1/4th second rule; or set a waypoint around the obstacle and navigate towards that.

avatar image Hamesh81 · Mar 06, 2012 at 06:03 PM 0
Share

Alright, I added the timer to the raycast. I also added the boolean "raycastHitting" which is set to true when the raycast hits something only. All the "look at" logic has a !raycastHitting condition now, please have a look at the updated script in the question above (it may take a few $$anonymous$$utes for the updates to go through though). Everything is working as it did before but it looks like the ray is being cast along the local x axis ins$$anonymous$$d of local z which is strange cos I'm using transform.forward. The boolean and timer are both public so I can watch them in the inspector as the game runs, everything looks like it is working as it should. Ins$$anonymous$$d of rotating 90 degrees, it is turning just a little bit though. Can you see what I am doing wrong? The raycast part is the very last section in the script. I've also uploaded a package of the scene I'm working with, if you have a spare moment is there any chance you could have a look at it? It is a very simple setup. Thanks so much for your help so far Owen, really appreciate your time.

Show more comments

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

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Obstacle Avoidance 0 Answers

Raycast Steering Problem 1 Answer

Camera rotation around player while following. 6 Answers

Raycast moves away from object when object is rotated. 1 Answer

Can't figure out how to make my raycast obstacle avoidance less jittery 3 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