Search Unity

Unity Editor Freezes During Play

Discussion in 'Scripting' started by ProtoZero, Mar 5, 2015.

  1. ProtoZero

    ProtoZero

    Joined:
    Mar 6, 2014
    Posts:
    5
    Hello everyone! I like to think I am an intermediate level user of Unity, and I am very familiar with C# and programming, but lately I have been stumped by the Unity editor freezing up during gameplay on my most recent changes. Allow me to elaborate. I am making a First Person Shooter, and I recently changed a script to support having different weapons and to handle playing audio in a loop for full auto weapons vs just playing the audio normally for semi auto weapons. Every since this update to my script, within a minute of playing (sometimes within the first three shots), the editor will lock up, the game will lock up, and the audio loop for my full auto weapon will continue to play indefinitely. The game also locks up on semi auto weapons, but their audio doesn't loop, which makes sense, as it's not set to loop in the Inspector for the audio source containing that sound effect. This is happening in Unity 4.6.3 and in the new 5.0 release.

    I have attempted to address it many ways. First, I have compressed all of my audio, and ran the game in the profiler to identify any performance hangs. I am getting over 100 fps, and don't see anything alarming before the editor suddenly freezes. I have encapsulated all of my updated functions with try/catch blocks to see if I am getting any System errors and report them (perhaps an array index out of bounds or null pointer), and I am finding nothing. Lastly, the hang seems most likely to be an infinite loop, so I have encapsulated every update function in Debug statements, reading "entered" and "exited" for each class's update. After running the game in the editor, I checked the console when the game froze to see if each class had a matching number of "entered" and "exited" debug statements. My goal here was to find odd parity on one of the sets of update debug statements, to give me an idea of which script to begin drilling down into and analyzing for infinite loop conditions, but to my dismay, each function had a matching amount of "entered" and "exited" statements.

    At this point, I am at a total loss. Unity community, if you could please advise me on how to debug this situation, I would be most grateful, as Unity itself is telling me nothing in the console, its sophisticated profiler is providing me with no red flags, and all of my debugging tricks have been pulled out of my debugging hat. I'm attaching the old version and the new version of the script that I changed before this nonsense began, in that order respectively, for you too look over and have context. In addition, I will provide links to the dropbox folder where you can get runnable game files to see the problem first hand.

    Here is a link to my project website, where you can click download and have access to all of the executable files in my dropbox folder.

    Old PerformAttack.cs
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PerformAttack : MonoBehaviour
    5. {
    6.         PlayerInventory inventory;
    7.        
    8.         public float cooldown = 0.2f;                          // weapon cooldown
    9.         public float range = 100.0f;                          // weapon range
    10.         public float damage = 30.0f;                         // weapon damage
    11.         public float controllerVibration = 1f;              // intensity of controller vibration on shoot
    12.         public ShotTypes shotType = ShotTypes.Piercing;    // weapon projectile type
    13.        
    14.         //particle systems for shots fired
    15.         public GameObject killShotEffect;
    16.         public GameObject standardShotEffect;
    17.         public GameObject bulletHole;
    18.  
    19.         // bullet sound effect
    20.         public AudioSource shootSound;
    21.  
    22.         // crosshair object to change crosshairs on hit
    23.         CrosshairScript crosshair;
    24.        
    25.         // local var for tracking weapon cooldown
    26.         float cooldownRemaining = 0.0f;
    27.  
    28.         // Start is called at script instantiation
    29.         void Start()
    30.         {
    31.             inventory = GetComponent<PlayerInventory>();
    32.             if (inventory == null)
    33.             {
    34.                 Debug.LogError("inventory is null on " + gameObject.name);
    35.             }
    36.  
    37.             // Set up weapon attributes for local control
    38.             DetectNewWeaponAttributes();
    39.  
    40.             // Instantiate variables  
    41.             crosshair = GameObject.FindGameObjectWithTag("Crosshair").GetComponent<CrosshairScript>();
    42.  
    43.             // Replace this line with finding the audio source of the actual gun  
    44.             //shootSound = Camera.main.transform.FindChild("gunarms").FindChild("Right").FindChild("ShootPoint").GetComponent<AudioSource>();
    45.  
    46.             // Check variable instantiations
    47.             if (crosshair == null)
    48.             {
    49.                 Debug.LogError("crosshair is null");
    50.             }
    51.         }
    52.  
    53.         // New update function uses InputManager
    54.         // Update is called once per frame
    55.         void Update()
    56.         {
    57.             // Decrement the cooldown by the amount of time since the last Update call  
    58.             cooldownRemaining -= Time.deltaTime;
    59.  
    60.             // If the Shoot was pressed and the cooldown time is expired...
    61.             if (InputManager.GetButton(InputManager.ACTION.SHOOT) && cooldownRemaining <= 0.0f)
    62.             {
    63.                 // TODO: move shootsound to shoot method, implement charge method and functionality here in Update()
    64.                 // Play the sound effect
    65.                 shootSound.Play();
    66.              
    67.                 // Reset the cooldown timer
    68.                 cooldownRemaining = cooldown;
    69.  
    70.                 // Cast a ray with the bullet trajectory and pass it to shoot to determine if it's a hit or not
    71.                 // and to animate the shot affects
    72.                 Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
    73.                 Shoot(shotType, ray);
    74.             }
    75.             else
    76.             {
    77.                 shootSound.Stop();
    78.             }
    79.         }
    80.  
    81.         /// <summary>
    82.         /// Used to force PerformAttack to check for updated values for weapon attributes in PlayerInventory's
    83.         /// currentweapon variable
    84.         /// </summary>
    85.         public void DetectNewWeaponAttributes()
    86.         {
    87.             // Get a copy of the Weapon Attributes for ease of use
    88.             WeaponAttributes currentWeaponAttributes = inventory.currentWeapon.GetComponent<WeaponAttributes>();
    89.             cooldown = currentWeaponAttributes.FireRate / 60f;
    90.             range = currentWeaponAttributes.Range;
    91.             damage = currentWeaponAttributes.Damage;
    92.             shotType = currentWeaponAttributes.ShotType;
    93.             killShotEffect = currentWeaponAttributes.KillShotEffect;
    94.             standardShotEffect = currentWeaponAttributes.StandardShotEffect;
    95.             bulletHole = currentWeaponAttributes.BulletHole;
    96.             shootSound = inventory.currentWeapon.GetComponent<AudioSource>();
    97.             crosshair = inventory.currentWeapon.GetComponent<CrosshairScript>();
    98.  
    99.             // Reset local control vars
    100.             cooldownRemaining = 0f;
    101.         }
    102.    
    103.         /*
    104.          * Method takes remaining HP of hit target and
    105.          * returns the appropriate bullet affect.
    106.          * TODO: support multiple shot effects per gun
    107.          * TODO: support multiple effects for visual variety
    108.          */
    109.         GameObject shotEffect (float hp)
    110.         {
    111.                 if (hp > 0.0f) {
    112.                         return standardShotEffect;
    113.                 } else {
    114.                         return killShotEffect;
    115.                 }
    116.         }
    117.    
    118.         /*
    119.          * Method 'shoots' the equiped weapon. Currently has two modes,
    120.          * normal, which is a straight single hit ray trace, and piercing,
    121.          * which is a piercing ray trace all. Piercing is the best use, since it
    122.          * is used to avoid a bug where you can shoot your own character controller.
    123.          *
    124.          * TODO: Add a physics based shoot that takes speeds and other attributes
    125.          *       for shooting rockets, charge shots, and slower moving projectiles
    126.          */
    127.         void Shoot (ShotTypes type, Ray ray)
    128.         {
    129.                 if (type == ShotTypes.Normal) {
    130.                        
    131.                         // Simple one hit raycast
    132.                         RaycastHit hitInfo;
    133.                         if (Physics.Raycast (ray, out hitInfo, range)) {
    134.                                 bool headshot = false;
    135.                                 Vector3 hitPoint = hitInfo.point;
    136.                                 GameObject pwnd = hitInfo.collider.gameObject;
    137.                                 //    Debug.Log (pwnd.name);
    138.                                 if (pwnd.name.Equals ("HeadshotDetector")) {
    139.                                         headshot = true;
    140.                                 }
    141.                                 HasHealth h = pwnd.GetComponent<HasHealth> ();
    142.                                 while (h == null && pwnd.gameObject.transform.parent != null) {
    143.                                         h = pwnd.gameObject.transform.GetComponentInParent<HasHealth> ();
    144.                                 }
    145.                                 bool animateEffect = true;
    146.                                 if (h != null) {
    147.                                         // This command is the same as:
    148.                                         //                    h.ReceiveDamage (damage);
    149.                                         // but for multiplayer too
    150.                                         PhotonView pv = h.GetComponent<PhotonView> ();
    151.                                         if (PhotonNetwork.player.ID != pv.ownerId) {
    152.                                                 if (pv == null) {
    153.                                                         Debug.LogError ("No PhotonView on damaged object!");
    154.                                                 } else {
    155.                                                         ArrayList args = new ArrayList ();
    156.                                                         if (headshot) {
    157.                                                                 args.Add (damage * 2f);
    158.                                                         } else {
    159.                                                                 args.Add (damage);
    160.                                                         }
    161.                                                         args.Add (PhotonNetwork.player.ID);
    162.                                                         pv.RPC ("ReceiveDamage", PhotonTargets.All, args.ToArray ());
    163.                                                 }
    164.                                                 Instantiate (shotEffect (h.CurrentHealth), hitPoint, Quaternion.LookRotation (-ray.direction));
    165.                                                 crosshair.Hit = true;
    166.                                         } else {
    167.                                                 animateEffect = false;
    168.                                         }
    169.                                 } else if (animateEffect) {
    170.                                         //use regular bulletricochet on inanimate objects
    171.                                         Instantiate (shotEffect (1), hitPoint, Quaternion.LookRotation (-ray.direction));
    172.                                        
    173.                                         //Debug.LogError ("Object has no health script!");
    174.                                 }
    175.                                 if (animateEffect) {
    176.                                         //leave a bullet hole
    177.                                         GameObject decal = (GameObject)Instantiate (bulletHole, hitPoint, Quaternion.LookRotation (hitInfo.normal));
    178.                                         decal.transform.parent = pwnd.transform;  
    179.                                         decal.transform.localPosition = new Vector3 (decal.transform.localPosition.x, decal.transform.localPosition.y, decal.transform.localPosition.z + 0.001f);                          
    180.                                 }
    181.                         }
    182.                 }
    183.                 if (type == ShotTypes.Piercing) {
    184.                        
    185.                         //more sophisticated piercing raycastall that ignores the player
    186.                         RaycastHit[] hitList = Physics.RaycastAll (ray);
    187.            
    188.                         for (int i = 0; i < hitList.Length; i++) {
    189.  
    190.                                 Vector3 hitPoint = hitList [i].point;
    191.                                 GameObject pwnd = hitList [i].collider.gameObject;
    192.                                 //Debug.Log (pwnd.name);
    193.                
    194.                                 bool headshot = false;
    195.                                 if (pwnd.name.Equals ("HeadshotDetector")) {
    196.                                         headshot = true;
    197.                                 }
    198.  
    199.                                 if (pwnd.GetComponent<FirstPersonController> () == null || pwnd.GetComponent<FirstPersonController> ().enabled == false) {
    200.                
    201.                                         HasHealth h = pwnd.GetComponent<HasHealth> ();
    202.                                         while (h == null && pwnd.gameObject.transform.parent != null) {
    203.                                                 h = pwnd.gameObject.transform.GetComponentInParent<HasHealth> ();
    204.                                         }
    205.                                         bool animateEffect = true;
    206.                                         if (h != null) {
    207.                                                
    208.                                                 // This command is the same as:
    209.                                                 //                    h.ReceiveDamage (damage);
    210.                                                 // but for multiplayer too
    211.                                                 PhotonView pv = h.GetComponent<PhotonView> ();
    212.                                                 if (PhotonNetwork.player.ID != pv.ownerId) {
    213.                                                         if (pv == null) {
    214.                                                                 Debug.LogError ("No PhotonView on damaged object!");
    215.                                                         } else {
    216.                                                                 ArrayList args = new ArrayList ();
    217.                                                                 if (headshot) {
    218.                                                                         args.Add (damage * 2f);
    219.                                                                 } else {
    220.                                                                         args.Add (damage);
    221.                                                                 }
    222.                                                                 args.Add (PhotonNetwork.player.ID);
    223.                                                                 pv.RPC ("ReceiveDamage", PhotonTargets.All, args.ToArray ());
    224.                                                                 //    Debug.Log (pwnd.name + " just took " + damage + " damage!");
    225.                                                         }
    226.                                                         // this is for drawing the effect from barrel
    227.                                                         Ray effectRay = new Ray (Camera.main.transform.FindChild ("gunarms").FindChild ("Right").
    228.                                                         FindChild ("ShootPoint").gameObject.transform.forward, hitPoint);
    229.                                        
    230.                                                         //TODO:BulletTracer         Instantiate(shotEffect(tracer), shootPoint, shootpoint.forward));
    231.                                                         Instantiate (shotEffect (h.CurrentHealth), hitPoint, Quaternion.LookRotation (-effectRay.direction));
    232.                                                         crosshair.Hit = true;
    233.                                                 } else {
    234.                                                         animateEffect = false;
    235.                                                 }
    236.                                         } else if (animateEffect) {
    237.                                                 //use regular bulletricochet on inanimate objects
    238.                                                 Instantiate (shotEffect (1), hitPoint, Quaternion.LookRotation (-ray.direction));
    239.                                                
    240.                                                 //Debug.LogError ("Object has no health script!");
    241.                                         }
    242.                                         if (animateEffect) {
    243.                                                 //leave a bullet hole
    244.                                                 GameObject decal = (GameObject)Instantiate (bulletHole, hitPoint, Quaternion.LookRotation (hitList [i].normal));
    245.                                                 decal.transform.parent = pwnd.transform;
    246.                                                 decal.transform.localPosition = new Vector3 (decal.transform.localPosition.x, decal.transform.localPosition.y, decal.transform.localPosition.z + 0.001f);
    247.                                         }
    248.                                 }  
    249.                         }
    250.                 }
    251.         }
    252. }
    253.  
    New PerformAttack.cs
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4.  
    5. public class PerformAttack : MonoBehaviour
    6. {
    7.         PlayerInventory inventory;
    8.        
    9.         public float cooldown = 0.2f;                          // weapon cooldown
    10.         public float range = 100.0f;                          // weapon range
    11.         public float damage = 30.0f;                         // weapon damage
    12.         public float controllerVibration = 1f;              // intensity of controller vibration on shoot
    13.         public ShotTypes shotType = ShotTypes.Piercing;    // weapon projectile type
    14.         public WeaponFireType fireType = WeaponFireType.SemiAuto; // Weapon fire type
    15.        
    16.         //particle systems for shots fired
    17.         public GameObject killShotEffect;
    18.         public GameObject standardShotEffect;
    19.         public GameObject bulletHole;
    20.  
    21.         // bullet sound effect
    22.         public AudioSource shootSound;
    23.  
    24.         // crosshair object to change crosshairs on hit
    25.         CrosshairScript crosshair;
    26.        
    27.         // local var for tracking weapon cooldown
    28.         float cooldownRemaining = 0.0f;
    29.  
    30.         bool weaponFireSoundIsPlaying = false;
    31.  
    32.         // Start is called at script instantiation
    33.         void Start()
    34.         {
    35.             inventory = GetComponent<PlayerInventory>();
    36.             if (inventory == null)
    37.             {
    38.                 Debug.LogError("inventory is null on " + gameObject.name);
    39.             }
    40.  
    41.             // Set up weapon attributes for local control
    42.             DetectNewWeaponAttributes();
    43.  
    44.             // Instantiate variables  
    45.             crosshair = GameObject.FindGameObjectWithTag("Crosshair").GetComponent<CrosshairScript>();
    46.  
    47.             // Replace this line with finding the audio source of the actual gun  
    48.             //shootSound = Camera.main.transform.FindChild("gunarms").FindChild("Right").FindChild("ShootPoint").GetComponent<AudioSource>();
    49.  
    50.             // Check variable instantiations
    51.             if (crosshair == null)
    52.             {
    53.                 Debug.LogError("crosshair is null");
    54.             }
    55.         }
    56.  
    57.         // New update function uses InputManager
    58.         // Update is called once per frame
    59.         void Update()
    60.         {
    61.             Debug.Log("PerformAttack Update entered");
    62.             try
    63.             {
    64.                 // Decrement the cooldown by the amount of time since the last Update call  
    65.                 cooldownRemaining -= Time.deltaTime;
    66.  
    67.                 // If the Shoot was pressed and the cooldown time is expired...
    68.                 if (InputManager.GetButton(InputManager.ACTION.SHOOT) && cooldownRemaining <= 0.0f)
    69.                 {
    70.                     // TODO: move shootsound to shoot method, implement charge method and functionality here in Update()
    71.                     // Play the sound effect
    72.                     if (fireType == WeaponFireType.SemiAuto)
    73.                     {
    74.                         shootSound.Play();
    75.                     }
    76.                     else if (fireType == WeaponFireType.FullAuto && !weaponFireSoundIsPlaying)
    77.                     {
    78.                         shootSound.Play();
    79.                         weaponFireSoundIsPlaying = true;
    80.                     }
    81.  
    82.                     // Reset the cooldown timer
    83.                     cooldownRemaining = cooldown;
    84.  
    85.                     // Cast a ray with the bullet trajectory and pass it to shoot to determine if it's a hit or not
    86.                     // and to animate the shot affects
    87.                     Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
    88.                     Debug.Log("Start Shoot");
    89.                     Shoot(shotType, ray);
    90.                     Debug.Log("End Shoot");
    91.                 }
    92.                 else if (!InputManager.GetButton(InputManager.ACTION.SHOOT) && weaponFireSoundIsPlaying)
    93.                 {
    94.                     shootSound.Stop();
    95.                     weaponFireSoundIsPlaying = false;
    96.                 }
    97.             }
    98.             catch (Exception e)
    99.             {
    100.                 Debug.LogError("Caught the mysterious bullshit exception otherwise known as " + e.ToString() + " in PerformAttack at the source " + e.Source.ToString());
    101.  
    102.             }
    103.             Debug.Log("PerformAttack Update exited");
    104.         }
    105.  
    106.         /// <summary>
    107.         /// Used to force PerformAttack to check for updated values for weapon attributes in PlayerInventory's
    108.         /// currentweapon variable
    109.         /// </summary>
    110.         public void DetectNewWeaponAttributes()
    111.         {
    112.             // Get a copy of the Weapon Attributes for ease of use
    113.             WeaponAttributes currentWeaponAttributes = inventory.currentWeapon.GetComponent<WeaponAttributes>();
    114.             if (currentWeaponAttributes.FireRate > 0)
    115.                 cooldown = 1f / currentWeaponAttributes.FireRate;
    116.             else cooldown = 1f;
    117.             range = currentWeaponAttributes.Range;
    118.             damage = currentWeaponAttributes.Damage;
    119.             shotType = currentWeaponAttributes.ShotType;
    120.             killShotEffect = currentWeaponAttributes.KillShotEffect;
    121.             standardShotEffect = currentWeaponAttributes.StandardShotEffect;
    122.             bulletHole = currentWeaponAttributes.BulletHole;
    123.             shootSound = inventory.currentWeapon.GetComponent<AudioSource>();
    124.             crosshair = inventory.currentWeapon.GetComponent<CrosshairScript>();
    125.             fireType = currentWeaponAttributes.FireType;
    126.  
    127.             // Reset local control vars
    128.             cooldownRemaining = 0f;
    129.         }
    130.    
    131.         /*
    132.          * Method takes remaining HP of hit target and
    133.          * returns the appropriate bullet affect.
    134.          * TODO: support multiple shot effects per gun
    135.          * TODO: support multiple effects for visual variety
    136.          */
    137.         GameObject shotEffect (float hp)
    138.         {
    139.                 if (hp > 0.0f) {
    140.                         return standardShotEffect;
    141.                 } else {
    142.                         return killShotEffect;
    143.                 }
    144.         }
    145.    
    146.         /*
    147.          * Method 'shoots' the equiped weapon. Currently has two modes,
    148.          * normal, which is a straight single hit ray trace, and piercing,
    149.          * which is a piercing ray trace all. Piercing is the best use, since it
    150.          * is used to avoid a bug where you can shoot your own character controller.
    151.          *
    152.          * TODO: Add a physics based shoot that takes speeds and other attributes
    153.          *       for shooting rockets, charge shots, and slower moving projectiles
    154.          */
    155.         void Shoot (ShotTypes type, Ray ray)
    156.         {
    157.                 if (type == ShotTypes.Normal) {
    158.                        
    159.                         // Simple one hit raycast
    160.                         RaycastHit hitInfo;
    161.                         if (Physics.Raycast (ray, out hitInfo, range)) {
    162.                                 bool headshot = false;
    163.                                 Vector3 hitPoint = hitInfo.point;
    164.                                 GameObject pwnd = hitInfo.collider.gameObject;
    165.                                 //    Debug.Log (pwnd.name);
    166.                                 if (pwnd.name.Equals ("HeadshotDetector")) {
    167.                                         headshot = true;
    168.                                 }
    169.                                 HasHealth h = pwnd.GetComponent<HasHealth> ();
    170.                                 int loopCounter = 0;
    171.                                 while (h == null && pwnd.gameObject.transform.parent != null) {
    172.                                         h = pwnd.gameObject.transform.GetComponentInParent<HasHealth> ();
    173.  
    174.                                         loopCounter++;
    175.                                         if (loopCounter > 500)
    176.                                         {
    177.                                             Debug.Log("Infinite Loop?");
    178.                                         }
    179.                                 }
    180.                                 bool animateEffect = true;
    181.                                 if (h != null) {
    182.                                         // This command is the same as:
    183.                                         //                    h.ReceiveDamage (damage);
    184.                                         // but for multiplayer too
    185.                                         PhotonView pv = h.GetComponent<PhotonView> ();
    186.                                         if (PhotonNetwork.player.ID != pv.ownerId) {
    187.                                                 if (pv == null) {
    188.                                                         Debug.LogError ("No PhotonView on damaged object!");
    189.                                                 } else {
    190.                                                         ArrayList args = new ArrayList ();
    191.                                                         if (headshot) {
    192.                                                                 args.Add (damage * 2f);
    193.                                                         } else {
    194.                                                                 args.Add (damage);
    195.                                                         }
    196.                                                         args.Add (PhotonNetwork.player.ID);
    197.                                                         pv.RPC ("ReceiveDamage", PhotonTargets.All, args.ToArray ());
    198.                                                 }
    199.                                                 Instantiate (shotEffect (h.CurrentHealth), hitPoint, Quaternion.LookRotation (-ray.direction));
    200.                                                 crosshair.Hit = true;
    201.                                         } else {
    202.                                                 animateEffect = false;
    203.                                         }
    204.                                 } else if (animateEffect) {
    205.                                         //use regular bulletricochet on inanimate objects
    206.                                         Instantiate (shotEffect (1), hitPoint, Quaternion.LookRotation (-ray.direction));
    207.                                        
    208.                                         //Debug.LogError ("Object has no health script!");
    209.                                 }
    210.                                 if (animateEffect) {
    211.                                         //leave a bullet hole
    212.                                         GameObject decal = (GameObject)Instantiate (bulletHole, hitPoint, Quaternion.LookRotation (hitInfo.normal));
    213.                                         decal.transform.parent = pwnd.transform;  
    214.                                         decal.transform.localPosition = new Vector3 (decal.transform.localPosition.x, decal.transform.localPosition.y, decal.transform.localPosition.z + 0.001f);                          
    215.                                 }
    216.                         }
    217.                 }
    218.                 if (type == ShotTypes.Piercing) {
    219.                        
    220.                         //more sophisticated piercing raycastall that ignores the player
    221.                         RaycastHit[] hitList = Physics.RaycastAll (ray);
    222.            
    223.                         for (int i = 0; i < hitList.Length; i++) {
    224.                             //Debug.Log(hitList.Length);
    225.                                 Vector3 hitPoint = hitList [i].point;
    226.                                 GameObject pwnd = hitList [i].collider.gameObject;
    227.                                 //Debug.Log (pwnd.name);
    228.                
    229.                                 bool headshot = false;
    230.                                 if (pwnd.name.Equals ("HeadshotDetector")) {
    231.                                         headshot = true;
    232.                                 }
    233.  
    234.                                 if (pwnd.GetComponent<FirstPersonController> () == null || pwnd.GetComponent<FirstPersonController> ().enabled == false) {
    235.                
    236.                                         HasHealth h = pwnd.GetComponent<HasHealth> ();
    237.                                         int loopCounter = 0;
    238.                                         while (h == null && pwnd.gameObject.transform.parent != null) {
    239.                                                 h = pwnd.gameObject.transform.GetComponentInParent<HasHealth> ();
    240.  
    241.                                                 loopCounter++;
    242.                                                 if (loopCounter > 500)
    243.                                                 {
    244.                                                     Debug.Log("Infinite Loop?");
    245.                                                 }
    246.                                         }
    247.                                         bool animateEffect = true;
    248.                                         if (h != null) {
    249.                                                
    250.                                                 // This command is the same as:
    251.                                                 //                    h.ReceiveDamage (damage);
    252.                                                 // but for multiplayer too
    253.                                                 PhotonView pv = h.GetComponent<PhotonView> ();
    254.                                                 if (PhotonNetwork.player.ID != pv.ownerId) {
    255.                                                         if (pv == null) {
    256.                                                                 Debug.LogError ("No PhotonView on damaged object!");
    257.                                                         } else {
    258.                                                                 ArrayList args = new ArrayList ();
    259.                                                                 if (headshot) {
    260.                                                                         args.Add (damage * 2f);
    261.                                                                 } else {
    262.                                                                         args.Add (damage);
    263.                                                                 }
    264.                                                                 args.Add (PhotonNetwork.player.ID);
    265.                                                                 pv.RPC ("ReceiveDamage", PhotonTargets.All, args.ToArray ());
    266.                                                                 //    Debug.Log (pwnd.name + " just took " + damage + " damage!");
    267.                                                         }
    268.                                                         // this is for drawing the effect from barrel
    269.                                                         Ray effectRay = new Ray (Camera.main.transform.FindChild ("gunarms").FindChild ("Right").
    270.                                                         FindChild ("ShootPoint").gameObject.transform.forward, hitPoint);
    271.                                        
    272.                                                         //TODO:BulletTracer         Instantiate(shotEffect(tracer), shootPoint, shootpoint.forward));
    273.                                                         Instantiate (shotEffect (h.CurrentHealth), hitPoint, Quaternion.LookRotation (-effectRay.direction));
    274.                                                         crosshair.Hit = true;
    275.                                                 } else {
    276.                                                         animateEffect = false;
    277.                                                 }
    278.                                         } else if (animateEffect) {
    279.                                                 //use regular bulletricochet on inanimate objects
    280.                                                 Instantiate (shotEffect (1), hitPoint, Quaternion.LookRotation (-ray.direction));
    281.                                                
    282.                                                 //Debug.LogError ("Object has no health script!");
    283.                                         }
    284.                                         if (animateEffect) {
    285.                                                 //leave a bullet hole
    286.                                                 GameObject decal = (GameObject)Instantiate (bulletHole, hitPoint, Quaternion.LookRotation (hitList [i].normal));
    287.                                                 decal.transform.parent = pwnd.transform;
    288.                                                 decal.transform.localPosition = new Vector3 (decal.transform.localPosition.x, decal.transform.localPosition.y, decal.transform.localPosition.z + 0.001f);
    289.                                         }
    290.                                 }  
    291.                         }
    292.                 }
    293.         }
    294. }
    295.  
     
  2. ProtoZero

    ProtoZero

    Joined:
    Mar 6, 2014
    Posts:
    5
    Hello Unity Community! I found the solution to my problem, so I am going to give you guys an update here in case anyone stumbles upon this later having similar editor freezes. Here is the problem area:

    1. while (h == null && pwnd.gameObject.transform.parent != null) {
    2. h = pwnd.gameObject.transform.GetComponentInParent<HasHealth> ();

    3. loopCounter++;
    4. if (loopCounter > 500)
    5. {
    6. Debug.Log("Infinite Loop?");
    7. }
    8. }
    This loop was intended to loop up from an object through all of its parents looking for a HasHealth script object that I wrote to manage how much health a player has left before dying. Ignore the debug statements there, this is checking if HasHealth of the parent is null, but it isn't updating the original object, pwnd, so that we can work our way up the ladder on the next iteration. In the end, this loop was checkin the same object again and again, causing an infinite loop. This error has been in my code for quite a while now, but it seems I have only discovered the error recently because I had added a slew of full auto weapons that increased my likelihood of hitting an object that does not have a HasHealth component added to it. I didn't notice the correlation right away because the bullets pierce map geometry using a raycastall, and I didn't see that I was also hitting some cube object colliders with some stray bullets.

    I'm very glad to have found the solution to my problem, and the problem was an infinite loop like I had originally suspected. From what I have read online, most Editor freezes are caused by infinite loop in your scripts. I am troubled that my strategy for discovering the loop by encapsulating the update methods in debug statements was ineffective. Logically, it should have worked, I would have seen an "entered" debug statement for PerformAttack.cs Update() that did not have a corresponding "exit" debug statement. It seems that Unity does not commit those Debug statements to the console when it iterates through their lines of code, but rather some time later, probably after each tick or frame, perhaps even after the Update method has fully executed its iteration. Keep this in mind folks! In the future, I would recommend watching your while loops very closely and making sure that you have good exit conditions, as well as ensuring your loop conditions are being set on false premises (mine was assuming we hit an object that belonged to a player who had a health script).

    Good luck on your projects, Unity Community!