- Home /
Enemy AI script causing Unity to crash (Javascript to C#)
I figured it'd be best to ask a new question since the issue is in a different script.
I've managed to convert the Enemy AI script to C# and Unity does not show any errors, however when trying to run after attaching the script to anything, the program freezes (both in the editor itself and as a standalone .exe). I can't shake the feeling that I'm just overlooking something simple (I'm guessing I messed up somewhere and made an infinite loop or something similar), but figured it'd be best to ask in case I'm wrong.
 using UnityEngine;
 using System.Collections;
 
 //We need a character controller for this script to run.
 [RequireComponent(typeof (CharacterController))]
 
 public class EnemyAI:MonoBehaviour
 {
     public float speed = 3.0f;
     public float rotationSpeed = 5.0f;
     public float shootRange = 15.0f;
     public float attackRange = 30.0f;
     public float shootAngle = 4.0f;
     public float dontComeCloserRange = 5.0f;
     public float delayShootTime = .35f;
     public float pickNextWaypointDistance = 2.0f;
     public Transform target;
     
     private float lastShot = -10.0f;
     
     void Start ()
     {
         //If we have no target at first, we'll set it to be our player.
         if(target == null && GameObject.FindWithTag("Player"))
         {
             target = GameObject.FindWithTag("Player").transform;
         }
         
         StartCoroutine("Patrol");
     }
     
     IEnumerator Patrol()
     {
         var curWayPoint = AutoWaypoint.FindClosest(transform.position);
         
         while(true)
         {
             var waypointPosition = curWayPoint.transform.position;
             //If we're close to a waypoint, we'll go ahead and pick the next one.
             if(Vector3.Distance(waypointPosition, transform.position) <
                 pickNextWaypointDistance)
             {
                 curWayPoint = PickNextWaypoint(curWayPoint);
             }
             
             //We'll attack the player if he is in sight.
             if(CanSeeTarget())
             {
                 StartCoroutine("AttackPlayer");
             }
             
             //Otherwise we'll just continue moving along the waypoints.
             MoveTowards(waypointPosition);
         }
     }
     
     bool CanSeeTarget()
     {
         //If the target is out of range, we cannot see it.
         if(Vector3.Distance(transform.position, target.position) > attackRange)
         {
             return false;
         }
         
         RaycastHit hit;
         if(Physics.Linecast(transform.position, target.position, out hit))
         {
             return hit.transform == target;
         }
         
         return false;
     }
     
     IEnumerator Shoot()
     {
         //We need to begin the shooting animation.
         animation.CrossFade("shoot", 0.3f);
         
         //We'll wait until half of the animation has played...
         yield return new WaitForSeconds(delayShootTime);
         
         //...fire the gun...
         BroadcastMessage("Fire");
         
         //...and finally, let the rest of the animation finish.
         yield return new WaitForSeconds(animation["shoot"].length - delayShootTime);
     }
     
     IEnumerator AttackPlayer()
     {
         //We'll set up the position the player was last visible.
         var lastVisiblePlayerPosition = target.position;
         while(true)
         {
             if(CanSeeTarget())
             {
                 //If our target is dead, we need to quit hunting.
                 if(target == null)
                 {
                     yield return null;
                 }
                 
                 //If the target is too far away, we need to give up the hunt.
                 var distance = Vector3.Distance(transform.position, target.position);
                 if(distance > shootRange * 3)
                 {
                     yield return null;
                 }
                 
                 lastVisiblePlayerPosition = target.position;
                 //If we aren't in the "Don't come closer range" yet, we'll move toward the last known
                 //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);
                 
                 //We'll start shooting at the player if he's in sight and within range.
                 if(distance < shootRange && angle < shootAngle)
                 {
                     StartCoroutine("Shoot");
                 }
                 else
                 {
                     StartCoroutine("SearchPlayer", lastVisiblePlayerPosition);
                     
                     //If at any point the player leaves visibility, we should stop attacking.
                     if(!CanSeeTarget())
                     {
                         yield return null;
                     }
                 }
             }
         }
     }
     
     IEnumerator SearchPlayer(Vector3 position)
     {
         //We'll run at the player, however if we can't see him for 3 seconds, we return to our patrol
         //route.
         float timeout = 3.0f;
         while(timeout > 0.0f)
         {
             MoveTowards(position);
             
             //We've found the player!
             if(CanSeeTarget())
             {
                 yield return null;
             }
             
             timeout -= Time.deltaTime;
         }
     }
     
     IEnumerator RotateTowards(Vector3 position)
     {
         SendMessage("SetSpeed", 0.0);
         
         var direction = position - transform.position;
         direction.y = 0;
         
         if(direction.magnitude < .1)
         {
             yield return null;
         }
         
         //Otherwise we have a target that we can see. As such, we'll rotate
         //towards our target.
         var targetPoint = target.position;
         var targetRotation = Quaternion.LookRotation(targetPoint -
             transform.position, Vector3.up);
         transform.rotation = Quaternion.Slerp(transform.rotation,
             targetRotation, Time.deltaTime * 2.0f);
     }
     
     IEnumerator MoveTowards(Vector3 position)
     {
         var direction = position - transform.position;
         direction.y = 0;
         
         if(direction.magnitude < .5)
         {
             SendMessage("SetSpeed", 0.0);
             yield return null;
         }
         
             //Otherwise we have a target that we can see. As such, we'll rotate
         //towards our target.
         var targetPoint = target.position;
         var targetRotation = Quaternion.LookRotation(targetPoint -
             transform.position, Vector3.up);
         transform.rotation = Quaternion.Slerp(transform.rotation,
             targetRotation, Time.deltaTime * 2.0f);
         
         //Now we should modify our speed so that we slow down when we aren't facing our target.
         var forward = transform.TransformDirection(Vector3.forward);
         var speedModifier = Vector3.Dot(forward, direction.normalized);
         speedModifier = Mathf.Clamp01(speedModifier);
         
         //Now we actually move our character.
         direction = forward * speed * speedModifier;
         CharacterController controller = GetComponent<CharacterController>();
         controller.SimpleMove(direction * speed);
         
         SendMessage("SetSpeed", speed * speedModifier,
             SendMessageOptions.DontRequireReceiver);
     }
     
     AutoWaypoint PickNextWaypoint(AutoWaypoint currentWaypoint)
     {
         //Let's find the waypoint where our character will have to turn the least.
         
         //This is the direction the character is walking.
         var forward = transform.TransformDirection(Vector3.forward);
         
         //The closer our two vectors are, the larger the dot product shall be.
         var best = currentWaypoint;
         float bestDot = -10.0f;
         
         foreach(AutoWaypoint cur 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;
     }
 }
I could, and I'm pretty sure I could simplify quite a few things in it. Of course that would ruin the point of this little project, namely converting the Javascript to C#.
Answer by Statement · Dec 26, 2011 at 01:40 PM
In AttackPlayer you have this code:
 while(true)
 {
     if(CanSeeTarget())
     {
         // Other code omitted
     }
 }
If CanSeeTarget return false, then it will probably return false again after and lock up.
Also Patrol seems to have a loop that will lock up. Coroutines doesn't work in C# as they do in JS. To branch into a child coroutine of a function you must yield return StartCoroutine(MoveTowards(waypointPosition)); etc. Just calling the coroutine function will not work.
- while() loop will lock up the system until they yield or return. Yah, it took me a while to get used to C# Coroutine, I now often write a void-return launching function along with every Coroutine so it just happens no matter what I write. 
Thanks, fixing up that code made it so that it didn't freeze upon starting.
Your answer
 
 
             Follow this Question
Related Questions
Converting Autowaypoint (JS) to C# 1 Answer
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
Distribute terrain in zones 3 Answers
How to access a static variable in c# from js 2 Answers
Reference a JS script in a C# script? 2 Answers
 koobas.hobune.stream
koobas.hobune.stream 
                       
                
                       
			     
			 
                