Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Unity Javascript - Basic AI

Discussion in 'Scripting' started by KiraHoshi, Dec 8, 2010.

  1. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    Hiya,

    Sorry to post another question but I require one last scripting assistance!
    I just really need a very basic AI script, as I don't understand AI very well. All the script needs to do is have the enemy object move towards the FPS Controller when in range, and when the enemy is within very close range, deal regular damage every 1 or 2 seconds.

    Any help would be greatly appreciated! I'm not concerned with animations just yet!

    Thanks
    Kira
     
  2. afalk

    afalk

    Joined:
    Jun 21, 2010
    Posts:
    164
    Grab the FPS tutorial from the Resources section here on the site - grab the scripts off the Robot. They do exactly what you are looking for and are in javascript as well.
     
  3. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    Hi, thanks for the reply. I tried looking at the scripts and fashioned something myself as it was getting a bit messy (they're using projectiles and have animations) but it needs work. I can't get rotation to work at the moment though.

    Code (csharp):
    1. var player : GameObject;
    2. var speed = 3.0;
    3. var range = 20.0;
    4. var hitRange = 3.0;
    5. var enemyDamage = 100.0;
    6.  
    7. function Start ()
    8. {
    9.      player = GameObject.FindGameObjectWithTag("1Player");
    10. }
    11.  
    12. function Update()
    13. {
    14.         //move towards player
    15.     var distance = Vector3.Distance( player.transform.position, transform.position);
    16.     if (distance > range)
    17.     {
    18.         return;
    19.     }
    20.    
    21.     else
    22.     {  
    23.     var delta = player.transform.position - transform.position;
    24.     delta.Normalize();
    25.     var moveSpeed = speed * Time.deltaTime;
    26.     transform.position = transform.position + (delta * moveSpeed);
    27.     if (distance < hitRange)
    28.     {
    29.         player.SendMessageUpwards
    30.     ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver);
    31.     }
    32.     }
    33. }
    Also, I've set it to do the damage within a smaller range. It is, obviously, calling it every update (which is probably very frame). Is there an easy way to reduce the frequency of that check being made whilst keep it regularly updated?
     
  4. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    Ok so I've made SOME progress with the rotation, but now for some reason when you get within range, he rotates 90 degrees on the x axis so that he's flying head first at me. =S Not sure how to change this. (I'll admit, I just adapted the code from the tutorial). Also, still not sure how to make the damage occur fewer times than once every frame (perhaps down to once every 1.5 seconds while within range?) I've tried WaitForSeconds(1.5); within the damage receiving script but it didn't agree.

    Any advances please? =]

    Ooo yea and here's my code thus far:

    Code (csharp):
    1. var player : GameObject;
    2. var speed = 6.0;
    3. var range = 10.0;
    4. var hitRange = 5.0;
    5. var enemyDamage = 10.0;
    6. var rotationSpeed = 5.0;
    7.  
    8. function Start ()
    9. {
    10.      player = GameObject.FindGameObjectWithTag("1Player");
    11. }
    12.  
    13. function Update()
    14. {
    15.         //move towards player
    16.     var distance = Vector3.Distance( player.transform.position, transform.position);
    17.     if (distance > range)
    18.     {
    19.         return;
    20.     }
    21.    
    22.     else
    23.     {  
    24.     var delta = player.transform.position - transform.position;
    25.     delta.Normalize();
    26.     delta.y = 0;
    27.     var moveSpeed = speed * Time.deltaTime;
    28.     transform.position = transform.position + (delta * moveSpeed);
    29.    
    30.     delta.y = 0;
    31.     transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(delta),
    32.     rotationSpeed * Time.deltaTime);
    33.     transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
    34.    
    35.     if (distance < hitRange)
    36.     {
    37.         player.SendMessageUpwards
    38.     ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver);
    39.     }
    40.     }
    41. }
     
  5. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    Sorry to bump but any advances guys?! =]
     
  6. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    Bump. =[
     
  7. Makandal

    Makandal

    Joined:
    Nov 3, 2010
    Posts:
    14
    Mathematically, one of the best way to model 1 moving object A searching another moving object B is to do:
    x->x+sign(x'-x)*speed
    y->y+sign(y'-y)*speed
    z->z+sign(z'-z)*speed

    knowing A(x,y,z) and B(x',y',z')

    It is also very fast and elegant. Condition is obvious: speed of A must be higher than B.

    EDIT: sorry, but this is not really AI...
     
  8. Mike Stampone

    Mike Stampone

    Joined:
    Dec 8, 2010
    Posts:
    21
    I am going to take a closer look at this code, but let me just say quickly that the conditional return branch is not necessary because there is no code following outside the conditional branches.

    Code (csharp):
    1. function Update()
    2. {
    3.   if ( x > 10)
    4.   {
    5.     return;
    6.   }
    7.   else
    8.   {
    9.     // code
    10.   }
    11.   // no code
    12. }
    can be reduced to

    Code (csharp):
    1. function Update()
    2. {
    3.   if ( x <= 10 )
    4.   {
    5.     // code
    6.   }
    7. }
     
    Last edited: Dec 9, 2010
  9. Mike Stampone

    Mike Stampone

    Joined:
    Dec 8, 2010
    Posts:
    21
    Hopefully this is a bit closer to the code you were wanting. You can add your Start() in as well.

    Code (csharp):
    1. var player : GameObject;
    2. var speed : float=6f;
    3. var range : float=10f;
    4. var hitRange : float=5f;
    5. var enemyDamage : float=10f;
    6. var rotationSpeed : float=5f;
    7. var damageTimer : float=0f;
    8.  
    9. function Update()
    10. {
    11.     //move towards player
    12.     var distance = Vector3.Distance(transform.position, player.transform.position);
    13.     if(distance<=range)
    14.     {  
    15.         var delta = player.transform.position - transform.position;
    16.         delta.Normalize();
    17.         delta.y = 0;
    18.         var moveSpeed = speed * Time.deltaTime;
    19.         transform.position = transform.position + (delta * moveSpeed);
    20.        
    21.         transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(delta),
    22.         rotationSpeed * Time.deltaTime);
    23.         transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
    24.    
    25.         damageTimer+=Time.deltaTime;
    26.         if (distance < hitRange  damageTimer>=1.5)
    27.         {
    28.             damageTimer=0f;
    29.             player.SendMessageUpwards
    30.                 ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver);
    31.         }
    32.     }
    33. }
     
  10. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    Hiya,

    Thank you ever so much! The damage timer works a treat now! Unfortunately though, the enemy is still rotating 90 degrees on the x axis so that he's flying head first at you, any ideas? I've tried a few things but I'm not sure if I'm going about it the right way).
     
  11. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    I've posted my rotation problem on Unity Answers but still no joy! Here's the link if you wish to look at the progress, any help is greatly appreciated!

    Rotation Problem
     
  12. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    Is there no one with the insight to find the more-than-likely simple problem that I am overlooking?
     
  13. Mike Stampone

    Mike Stampone

    Joined:
    Dec 8, 2010
    Posts:
    21
    I will have another look. Is it possible that the MeshRenderer is rotated 90 or -90 on the x axis, but the parent GameObject is not?
     
  14. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    I am so sorry to all of you trying to help me! I can't believe I overlooked something so simple! Thank you for pointing me in the direction Mike Stampone, it was the fact that I had to rotate my model 270 degrees around the x to get him stood up right in Unity, so when transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0); was called it set it back to 0. Just changed that to transform.eulerAngles = Vector3(270, transform.eulerAngles.y, 0); and it works fine. Again, I sincerely apologise for being so idiotic!

    Thanks again for all of your help, I still learn a lot!
    Kira
     
  15. Mike Stampone

    Mike Stampone

    Joined:
    Dec 8, 2010
    Posts:
    21
    Just thought I would add a couple comments, as it made it easier for me to read. You can take them or leave them. Anyway, your "enemy" should not be rotating in the x axis, because you throw away your x and z rotation with :

    transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);

    One of your GameObjects within the "enemy" must be rotated 90 or -90 in the x axis.

    At the moment, the "enemy" will point it's +z axis toward the "player". I assume this is because forward is Vector3(0,0,1) in Unity.

    Code (csharp):
    1. var player : GameObject;
    2. var speed : float=6f;
    3. var range : float=10f;
    4. var hitRange : float=5f;
    5. var enemyDamage : float=10f;
    6. var rotationSpeed : float=5f;
    7. var damageTimer : float=0f;
    8.  
    9. function Start()
    10. {
    11.     player = GameObject.FindGameObjectWithTag("1Player");
    12. }
    13.  
    14. function Update()
    15. {
    16.     // Move the Player
    17.     var distance = Vector3.Distance(transform.position, player.transform.position);
    18.     if(distance<=range)
    19.     {
    20.     // Translate
    21.         var delta = player.transform.position - transform.position;
    22.         delta.Normalize();
    23.         delta.y = 0;
    24.         var moveSpeed = speed * Time.deltaTime;
    25.         transform.position = transform.position + (delta * moveSpeed);
    26.  
    27.     // Rotate
    28.         transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(delta), rotationSpeed * Time.deltaTime);
    29.     transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
    30.  
    31.     // Apply damage every 1.5 seconds
    32.         damageTimer+=Time.deltaTime;
    33.         if (distance < hitRange  damageTimer>=1.5)
    34.         {
    35.             damageTimer=0f;
    36.             player.SendMessageUpwards
    37.             ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver);
    38.         }
    39.     }
    40. }
     
  16. Mike Stampone

    Mike Stampone

    Joined:
    Dec 8, 2010
    Posts:
    21
    Ah, my bad. You posted while I was posting! Great, I am glad you solved it.
     
  17. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    Thank you for the help, sorry for making you go through all of that for pretty much nothing! Just a simple mistake made by myself! I really appreciate all of your help, this forum is a great place to go for help. :)

    EDIT: I was thinking that I would like to add some code to make the zombie stop moving towards you if say the distance is 1.5 so that it doesn't move inside you, but make it continue rotating towards you regardless of the distance. Could this be done with a simple check before the movement code? I think I need to start separating the things in to methods now to make the code cleaner.
     
    Last edited: Dec 12, 2010
  18. KiraHoshi

    KiraHoshi

    Joined:
    Nov 17, 2010
    Posts:
    29
    Sorry to post again but I'm quite chuffed with my code right now! It may not be "proper" AI, nor particularly advanced or have extended functionality but it works and does a simple job relatively well. I know that when I was first trying to get this script together, I was desperately looking for ANY starting point to work off of (I hit lucky and found a thread which started me off) and think that this may be helpful to those in a similar situation.

    So here's the code so far, it currently moves towards you (the game object with tag "1player") as well as rotate towards you. When it gets in to a certain range, it starts doing damage in regular time intervals and then when within a portion of that "hit range" it'll stop moving towards you, but will continue to rotate towards you and keeps damaging you.

    Code (csharp):
    1. var player : GameObject;
    2. var speed : float=6f;
    3. var range : float=15f;
    4. var hitRange : float=6f;
    5. var enemyDamage : float=10f;
    6. var rotationSpeed : float=5f;
    7. var damageTimer : float=0f;
    8. var delta : Vector3;
    9. var distance;
    10.  
    11. function Start()
    12. {
    13.     player = GameObject.FindGameObjectWithTag("1Player");
    14. }
    15.  
    16. function Update()
    17. {
    18.     //calculate the enemy's distance from player and do a check to see if we should
    19.         //progress then call the necessary methods
    20.  
    21.     distance = Vector3.Distance(transform.position, player.transform.position);
    22.     if(distance<=range)
    23.     {  
    24.         MoveTowards();
    25.         RotateTowards();
    26.         AttackPlayer();
    27.     }
    28. }
    29.  
    30. function MoveTowards()
    31. {
    32.     delta = player.transform.position - transform.position;
    33.     delta.Normalize();
    34.     delta.y = 0;
    35.     if(distance<=(hitRange/1.5))
    36.     {
    37.         return;
    38.     }
    39.     var moveSpeed = speed * Time.deltaTime;
    40.     transform.position = transform.position + (delta * moveSpeed);
    41. }
    42.  
    43. function RotateTowards()
    44. {
    45.     transform.rotation = Quaternion.RotateTowards (transform.rotation, Quaternion.LookRotation(delta), rotationSpeed);
    46.     transform.rotation = Quaternion.Euler(0, transform.eulerAngles.y, 0);
    47. }
    48.  
    49. function AttackPlayer()
    50. {
    51.     damageTimer+=Time.deltaTime;
    52.     if (distance < hitRange  damageTimer>=1.5)
    53.     {
    54.         damageTimer=0f;
    55.         player.SendMessageUpwards
    56.         ("ApplyDamage", enemyDamage, SendMessageOptions.DontRequireReceiver);
    57.     }
    58. }
     
    Last edited: Dec 14, 2010
  19. jakeman72202

    jakeman72202

    Joined:
    Oct 27, 2014
    Posts:
    1
    This is my Ai in my game im making actualy my first AI Script ive made
    Its In Javascript


    //This is my code
    var Distance;
    var Target : Transform;
    var LookAtRange = 25.0;
    var AttackRange = 16.0;
    var MoveSpeed = 10;
    var chaserange = 16.0;
    var Damping = 10.0;
    var Damage : int = 45;
    //Attack Timer Vars
    var art = 1;
    private var attackTime : float;
    var damage : int = 45;
    var controller : CharacterController;
    var gravity : float = 99.90;
    private var moveDirection : Vector3 = Vector3.zero;
    function Start ()
    {
    attackTime = Time.time;
    }
    function Update ()
    {
    Distance = Vector3.Distance(Target.position, transform.position);

    if (Distance < LookAtRange)
    {
    renderer.material.color = Color.yellow;
    LookAt();
    }
    if (Distance > LookAtRange)
    {
    renderer.material.color = Color.blue;
    }

    if (Distance < AttackRange)
    {
    attack();
    }
    else if (Distance < chaserange)
    {
    renderer.material.color = Color.red;
    chase();
    }
    }
    function LookAt()
    {
    var rotation = Quaternion.LookRotation(Target.position - transform.position);
    transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * Damping);
    }
    function chase()
    {
    moveDirection = transform.forward;
    moveDirection *= MoveSpeed;

    moveDirection.y -= gravity * Time.deltaTime;
    controller.Move(moveDirection * Time.deltaTime);

    }
    function attack()
    {
    {
    if (Time.time > attackTime)
    {
    Target.SendMessage("Applypdmg", Damage, SendMessageOptions.DontRequireReceiver);
    attackTime = Time.time + art;
    }
    }
    }