Search Unity

Resolved Gameobject script freezes unity upon play

Discussion in 'Scripting' started by Yuenciel, Jan 6, 2020.

  1. Yuenciel

    Yuenciel

    Joined:
    Dec 20, 2018
    Posts:
    15
    I created this script to let the object roam freely when it doesn't detect the player and will engage combat when it does. I also included the codes for it's animations.
    The thing is, I have 2 scenes,TestingScene and GameScene. On TestingScene, I encountered no problem other than the model stuttering when the player's within a certain distance. On the other hand, the GameScene freezes when I hit the play button. Disabling the script from the problem prefab somehow lets Unity runs normally.
    Here's the script :

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class EnemyController : MonoBehaviour
    6. {
    7.     public Animator myAnimator;
    8.     private Collider myCollider;
    9.     private Rigidbody rb;
    10.     private Vector3 startPosition;
    11.     private Vector3 randomDirection;
    12.     private Coroutine combatCor;
    13.     private Coroutine idleCor;
    14.  
    15.     public GameObject pointer;
    16.     public GameObject deathModel;
    17.     private GameObject player;
    18.     public GameObject firePoint;
    19.     public GameObject projectile;
    20.     public float minFireRate = 2.0f;
    21.     public float maxFireRate = 5.0f;
    22.     private float nextFire;
    23.     public float combatMovementSpeed = 10.0f;
    24.     private bool fired = false;
    25.     private bool combat = false;
    26.     private bool freeRoam = false;
    27.  
    28.     public float awareRadius = 10.0f;
    29.  
    30.     private Vector3 newPos;
    31.     private bool newPosIsSet;
    32.  
    33.     public float roamRadius;
    34.     public float walkingSpeed = 2.0f;
    35.     public float minIdleTime = 3.0f;
    36.     public float maxIdleTime = 6.0f;
    37.     private bool nextDestinationSet;
    38.  
    39.  
    40.     // Start is called before the first frame update
    41.     void Start()
    42.     {
    43.         myCollider = GetComponent<CapsuleCollider>();
    44.         rb = GetComponent<Rigidbody>();
    45.  
    46.         player = GameObject.FindWithTag("Player");
    47.         startPosition = transform.position;
    48.         FreeRoam();
    49.     }
    50.  
    51.     // Update is called once per frame
    52.     void Update()
    53.     {
    54.         float checkPlayerDistance = Vector3.Distance(player.transform.position, transform.position);
    55.         float roundedDistance = Mathf.Round(checkPlayerDistance);
    56.         if (checkPlayerDistance <= awareRadius)
    57.         {
    58.             combat = true;
    59.             freeRoam = false;
    60.         }
    61.         else if (roundedDistance >= awareRadius + 5.0f && freeRoam == false)
    62.         {
    63.             Debug.Log("Enemy disengage !");
    64.             combat = false;
    65.             freeRoam = true;
    66.             FreeRoam();
    67.         }
    68.  
    69.         //--------------------------------------------------------------------------------------------------
    70.         //Combat Mode
    71.         //--------------------------------------------------------------------------------------------------
    72.  
    73.         if (combat == true)
    74.         {
    75.             pointer.SetActive(true);
    76.             nextDestinationSet = false;
    77.             transform.LookAt(player.transform.position);
    78.             if (roundedDistance > 5f)
    79.             {
    80.                 transform.position = Vector3.MoveTowards(transform.position, player.transform.position, Time.deltaTime * combatMovementSpeed);
    81.                 myAnimator.SetTrigger("isIdle");
    82.                 myAnimator.ResetTrigger("isWalking");
    83.             }
    84.             else
    85.             {
    86.                 transform.position += -transform.forward * Time.deltaTime * combatMovementSpeed;
    87.                 myAnimator.SetTrigger("isIdle");
    88.                 myAnimator.ResetTrigger("isWalking");
    89.             }
    90.  
    91.             if (Time.time > nextFire)
    92.             {
    93.                 nextFire = Time.time + Random.Range(minFireRate,maxFireRate);
    94.                 Fire();
    95.             }
    96.         }
    97.  
    98.         //--------------------------------------------------------------------------------------------------
    99.         //Roaming Mode
    100.         //--------------------------------------------------------------------------------------------------
    101.  
    102.         if (nextDestinationSet == true)
    103.         {
    104.             myAnimator.SetTrigger("isIdle");
    105.             myAnimator.ResetTrigger("isWalking");
    106.             transform.position = Vector3.MoveTowards(transform.position, randomDirection, Time.deltaTime * walkingSpeed);
    107.             if (transform.position == randomDirection)
    108.             {
    109.                 nextDestinationSet = false;
    110.                 Debug.Log("IdleTime");
    111.                 myAnimator.SetTrigger("isWalking");
    112.                 myAnimator.ResetTrigger("isIdle");
    113.                 idleCor = StartCoroutine(IdleTime());
    114.             }
    115.         }
    116.     }
    117.  
    118.     void FreeRoam()
    119.     {
    120.         Debug.Log("FreeRoam");
    121.         pointer.SetActive(false);
    122.         freeRoam = true;
    123.         randomDirection = Random.insideUnitSphere * roamRadius;
    124.         randomDirection.y = 0;
    125.         float checkDistance = Vector3.Distance(startPosition, randomDirection);
    126.         float distance = Vector3.Distance(transform.position, randomDirection);
    127.         Debug.Log(randomDirection);
    128.         if (checkDistance <= roamRadius)
    129.         {
    130.             Debug.Log("Next destination is set");
    131.             Vector3 currentPosition = transform.position;
    132.             transform.LookAt(randomDirection);
    133.             nextDestinationSet = true;
    134.         }
    135.         else if (distance <= 2)
    136.         {
    137.             FreeRoam();
    138.         }
    139.         else
    140.         {
    141.             FreeRoam();
    142.         }
    143.     }
    144.  
    145.     IEnumerator IdleTime()
    146.     {
    147.         yield return new WaitForSeconds(Random.Range(minIdleTime, maxIdleTime));
    148.         if(combat == false)
    149.         FreeRoam();
    150.     }
    151.  
    152.     void OnCollisionEnter(Collision other)
    153.     {
    154.         if (other.gameObject.tag == "PlayerProjectile")
    155.         {
    156.             Instantiate(deathModel, transform.position, transform.rotation);
    157.             Destroy(gameObject);
    158.         }
    159.     }
    160.  
    161.     void Fire()
    162.     {
    163.         Instantiate(projectile, firePoint.transform.position, transform.rotation);
    164.     }
    165. }
    166.  
     
  2. ZO5KmUG6R

    ZO5KmUG6R

    Joined:
    Jul 15, 2010
    Posts:
    490
    Looks like a potential path to a stack overflow. Lines 137 and 141 could call FreeRoam recursively.
     
    Yuenciel and Joe-Censored like this.
  3. Yuenciel

    Yuenciel

    Joined:
    Dec 20, 2018
    Posts:
    15
    I removed line 135 ~ 139, and unity still freezes. By the way, what does stack overflow means? I'm not really experienced in coding.
     
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Basically, it means FreeRoam calls FreeRoam which calls FreeRoam which calls FreeRoam.....
    Each time you call a function it gets put on the "stack" until it finishes; the stack has a limited (though very large) capacity, so if you call the same function within itself repeatedly, it overflows.

    Calling a function from inside itself is called "recursion", and if you're not explicitly trying to use recursion for a specific reason (and know how to avoid situations like this), you should not really ever try to call a function from inside itself.

    If you deleted 135 - 139, you still have the "else" at the end that will still call itself recursively.
     
    Yuenciel and Joe-Censored like this.
  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    The "stack" is where your program stores local variables. Also, when you call a function, it adds some information to the stack to remember where you were, so it can go back there once the other function finishes.

    A "stack overflow" is when the stack runs out of space and your program can't continue because it doesn't have any more room for that stuff.

    A stack overflow is usually the result of infinite recursion, where you keep calling new functions but not finishing them and so you have to keep adding more and more information onto the stack to keep track of where you need to go back to when you're done. (It can happen for other reasons, but this is the main one.)



    When one of your scripts freezes Unity, that usually means you are stuck in some sort of infinite loop or infinite recursion so that your program never finishes what it's trying to do.
     
    Yuenciel and Joe-Censored like this.
  6. Yuenciel

    Yuenciel

    Joined:
    Dec 20, 2018
    Posts:
    15
    WOAH THANKS ! I changed that part to ...
    Code (CSharp):
    1.     void FreeRoam()
    2.     {
    3.         Debug.Log("FreeRoam");
    4.         pointer.SetActive(false);
    5.         freeRoam = true;
    6.         randomDirection = Random.insideUnitSphere * roamRadius;
    7.         randomDirection.y = 0;
    8.         float checkDistance = Vector3.Distance(startPosition, randomDirection);
    9.         float distance = Vector3.Distance(transform.position, randomDirection);
    10.         Debug.Log(randomDirection);
    11.         if (checkDistance <= roamRadius)
    12.         {
    13.             Debug.Log("Next destination is set");
    14.             Vector3 currentPosition = transform.position;
    15.             transform.LookAt(randomDirection);
    16.             nextDestinationSet = true;
    17.         }
    18.         else
    19.         {
    20.             nextDestinationSet = false;
    21.         }
    22.     }
    ... and it worked ! Oh gosh I'm so happy. Thank you for all your support guys !