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 tanthalas · Dec 22, 2011 at 10:35 AM · c#

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;
     }
 }
Comment
Add comment · Show 2
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 Lo0NuhtiK · Dec 22, 2011 at 10:57 AM 0
Share

agh! too much code, kill it!

avatar image tanthalas · Dec 26, 2011 at 01:31 PM 0
Share

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#.

1 Reply

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

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.

Comment
Add comment · Show 2 · 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 by0log1c · Dec 26, 2011 at 02:44 PM 0
Share
  • 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.

avatar image tanthalas · Dec 30, 2011 at 05:46 AM 0
Share

Thanks, fixing up that code made it so that it didn't freeze upon starting.

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

7 People are following this question.

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

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


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