Search Unity

Smart AI Object Avoidance In Very Little Code

Discussion in 'Scripting' started by DayyanSisson, Nov 29, 2012.

  1. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    I've created a simple AI in a couple minutes to try and see if I could create an AI that avoided objects without a hugely complicated system. I've done that, but its extremely brute and rugged. The basic idea was that the AI would raycast in 5 directions (forward, left, right, in between right and forward, and in between left and forward) and that it would use the information gained from the raycasts to make decisions. Its rotation speed is based off the distance of the forward raycast (the closer a wall or other object is to the AI, the faster it turns), whether or not it turns left or right is based off whether or not whether there's more distance on the left raycast or on the right. Here's a small demo showing it in action.

    And here's the code:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SmartAI : MonoBehaviour {
    5.  
    6.     public float speed;
    7.     public float speedModifier = 3;
    8.     public float rotateSpeed;
    9.     public int rotateSpeedModifier;
    10.  
    11.     private RaycastHit fHit;
    12.     private RaycastHit rHit;
    13.     private RaycastHit riHit;
    14.     private RaycastHit lHit;
    15.     private RaycastHit leHit;
    16.  
    17.     private Transform student;
    18.  
    19.     void Awake () {
    20.  
    21.         student = transform;
    22.     }
    23.  
    24.     void Update () {
    25.    
    26.         if(Physics.Raycast(student.position, student.forward, out fHit, 1000)){
    27.             Vector3 rightDir = student.forward + student.right;
    28.             Vector3 leftDir = student.forward - student.right;
    29.             Physics.Raycast(student.position, rightDir, out rHit, 1000);
    30.             Physics.Raycast(student.position, leftDir, out lHit, 1000);
    31.             Physics.Raycast(student.position, student.right, out riHit, 1000);
    32.             Physics.Raycast(student.position, -student.right, out leHit, 1000);
    33.             rotateSpeed = rotateSpeedModifier/fHit.distance;
    34.             speed = speedModifier*fHit.distance;
    35.             if(((lHit.distance+leHit.distance)/2) > ((rHit.distance+riHit.distance)/2)){
    36.                 student.Rotate(Vector3.up, -rotateSpeed);
    37.             }else{
    38.                 student.Rotate(Vector3.up, rotateSpeed);
    39.             }
    40.             student.Translate(Vector3.forward * speed * Time.deltaTime);
    41.         }
    42.     }
    43. }
    Well as you can see, the AI does have a couple problems. The speed is controlled by the distance so it jumps to large speeds sometimes but thats an easy fix. The major problem is that sometimes the AI spazzes out and starts rotating left and right extremely quickly. I want to be able to fix this and find ways to overall make this better. The reason I believe this happens is because the distance between the left and the right is about the same so it starts trying to rotate left and right. I tried to solve this problem by checking to see if the distances were approximately the same and then choose a random direction to turn:

    Code (csharp):
    1. if((Mathf.Approximately(((rHit.distance+riHit.distance)/2), ((lHit.distance+leHit.distance)/2)))){
    2.     if(Random.value > 0.5f){
    3.         student.Rotate(Vector3.up, -rotateSpeed);
    4.     }else{
    5.         student.Rotate(Vector3.up, rotateSpeed);
    6.     }
    7. }
    But that didn't work. Any ideas?

    Final Code

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SmartAI : MonoBehaviour {
    5.  
    6.     public float speed;
    7.     public float speedModifier = 3;
    8.     public float rotateSpeed;
    9.     public int rotateSpeedModifier;
    10.  
    11.     private RaycastHit fHit;
    12.     private RaycastHit rHit;
    13.     private RaycastHit riHit;
    14.     private RaycastHit lHit;
    15.     private RaycastHit leHit;
    16.  
    17.     private Transform student;
    18.  
    19.     void Awake () {
    20.  
    21.         student = transform;
    22.     }
    23.  
    24.     void Update () {
    25.    
    26.         if(Physics.Raycast(student.position, student.forward, out fHit, 1000)){
    27.             Vector3 rightDir = student.forward + student.right;
    28.             Vector3 leftDir = student.forward - student.right;
    29.             Physics.Raycast(student.position, rightDir, out rHit, 1000);
    30.             Physics.Raycast(student.position, leftDir, out lHit, 1000);
    31.             Physics.Raycast(student.position, student.right, out riHit, 1000);
    32.             Physics.Raycast(student.position, -student.right, out leHit, 1000);
    33.             rotateSpeed = rotateSpeedModifier/fHit.distance;
    34.             speed = speedModifier*fHit.distance;
    35.             if(((lHit.distance+leHit.distance)/2) > ((rHit.distance+riHit.distance)/2)){
    36.                 student.Rotate(Vector3.up, -rotateSpeed);
    37.             }else if(((lHit.distance+leHit.distance)/2) < ((rHit.distance+riHit.distance)/2)){
    38.                 student.Rotate(Vector3.up, rotateSpeed);
    39.             }else if((Mathf.Approximately(((rHit.distance+riHit.distance)/2), ((lHit.distance+leHit.distance)/2)))){
    40.                 if(Random.value > 0.5f){
    41.                     student.Rotate(Vector3.up, -rotateSpeed);
    42.                 }else{
    43.                     student.Rotate(Vector3.up, rotateSpeed);
    44.                 }
    45.             }
    46.             student.Translate(Vector3.forward * speed * Time.deltaTime);
    47.         }
    48.     }
    49. }
    Another thing I noticed is that the AI reacts slightly differently every time I run the webplayer. Funny how much 0.0001 units off effects the whole path.
     
    Last edited: Nov 29, 2012
  2. lockbox

    lockbox

    Joined:
    Feb 10, 2012
    Posts:
    519
    I didn't go line-by-line through your code, but perhaps storing the last direction turned and selecting that direction when the distances are equal might solve your issue - or perhaps just go straight and don't turn at all.
     
  3. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Well the function rarely gets called at all so it may need a completely new method.
     
  4. NewDeveloper

    NewDeveloper

    Joined:
    Aug 25, 2012
    Posts:
    153
    I used a lot raycasts, and they are not the way to do avoidance!
    You can use them to shoot a projectile, but for avoidance is not the best way.
    Now I want to attach you an example of a developer who I did not remeber which published this source in his site.
    If you want to do something with vehicles as I seen in your posts, or something with ai as here, you can work with me.
    Enjoy
     

    Attached Files:

  5. NewDeveloper

    NewDeveloper

    Joined:
    Aug 25, 2012
    Posts:
    153
    Comparison between this two ways is:

    Tell me, when you drive a car, or you walk in a street, Do you only check a line, or a complete area with your eyes?
    I think that you check a complete area which is visible to your eyes. This you can get only with the script i sent before
     
  6. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Yes that ran through my mind? Is it possible to do that? Try something like Vector3.Angle but would work the same as raycasts? Or would I have to create a mesh that simulates that and use triggers?
     
  7. NewDeveloper

    NewDeveloper

    Joined:
    Aug 25, 2012
    Posts:
    153
    This works really great, I am developing a wonderfull racing ai. We can work together if you want, It's now my passion develop AI.
    You don't need to create a mesh. and this doesn't work as raycasts, but really better.
    In raycasts you have to develop the conditions:
    If FrontLeft is active then avoid to this new waypoints. That is really bad, specially if we are talking about vehicle ai.
    With this you can get the avoid system with just a formula.
    Tomorrow I am going to test it on. And I will let you know. Depending on result I can also send you the script.
    See you tomorrow. Good bye!