Tasharen Entertainment Forum

Support => NGUI 3 Support => Topic started by: retn on July 08, 2014, 08:04:45 PM

Title: EventDelegate causing infinite loop
Post by: retn on July 08, 2014, 08:04:45 PM
Hey Guys,

i have NGUI version. 3.6.7

My problem is the following. If i use EventDelegates on a UIPlayTween script, its causing an infinite loop and unity crashs.


  1. using UnityEngine;
  2. using System.Collections;
  3. using Net.MobileGame1.Core.Application;
  4.  
  5. public class ngui {
  6.  
  7.         private GameObject lobbyGameObject;
  8.         private UIPlayTween[] letsPlayTween;
  9.  
  10.         public ngui () {
  11.         }
  12.  
  13.         public void start () {
  14.                 // instanciate new gui nui root
  15.                 GameObject g1 = Resources.Load ("Gui/Lobby/Lobby") as GameObject;
  16.                 lobbyGameObject = GameObject.Instantiate (g1) as GameObject;           
  17.                 // lets get the tween script, from the button to be pressed
  18.                 GameObject letsPlayGameObject = GameObject.FindGameObjectWithTag (TagManager.GUI_LOBBY_LETSPLAY_BUTTON);
  19.                 letsPlayTween = letsPlayGameObject.GetComponents<UIPlayTween> ();
  20.                 // lets add a function to the eventhandler
  21.                 letsPlayTween[1].onFinished.Add (new EventDelegate(OnFinished));
  22.         }              
  23.                
  24.         public void close () {
  25.                 UnityEngine.Object.Destroy(lobbyGameObject);
  26.         }
  27.  
  28.         // callback
  29.         public void OnFinished () {
  30.                 //close previous
  31.                 close ();              
  32.                 start();
  33.         }
  34. }
  35.  

When i call the function outside of the ngui spec, its working like a cham.

  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public class test : MonoBehaviour {
  5.  
  6.         // global ngui instance, changes on click
  7.         public static ngui n;
  8.  
  9.         // Use this for initialization
  10.         void Start () {
  11.                 n = new ngui ();
  12.                 n.start ();
  13.         }
  14.                
  15.         public void OnGUI () {
  16.                 // this works like a cham
  17.                 if (GUI.Button (new Rect(0, 0, 200, 20), "refresh")) {
  18.                         n.OnFinished();
  19.                 }
  20.         }
  21. }
  22.  


Kind regards
retn
Title: Re: EventDelegate causing infinite loop
Post by: grofie on July 09, 2014, 08:17:40 AM
hi retn,

we used to add event delegates like that:

  1. EventDelegate.Add(letsPlayTween[1].onFinished, OnFinished);
(instead of letsPlayTween[1].onFinished.Add (new EventDelegate(OnFinished)); )

But what are you trying to achieve? Loading from resources, creating and destroying the lobby endless times does not sound like good practice and cost lots of time and work for the garbage collector.

Can't you refresh the values of the lobby instead?
Title: Re: EventDelegate causing infinite loop
Post by: retn on July 09, 2014, 08:39:47 AM
Hey grofie,

thanks for reply. Your suggestion is good.
It sovled the problem. Unity doesnt crash anymore.

Indeed, adding the delegate in my way before, caused the execution loop inside ngui to an infinite loop.

  1. public class ngui {
  2.  
  3.         private GameObject lobbyGameObject;
  4.  
  5.         public void start () {
  6.                 // instanciate new gui nui root
  7.                 GameObject g1 = Resources.Load ("Gui/Lobby/Lobby") as GameObject;
  8.                 lobbyGameObject = GameObject.Instantiate (g1) as GameObject;   
  9.  
  10.                 GameObject letsPlayGameObject = GameObject.FindWithTag (TagManager.GUI_LOBBY_LETSPLAY_BUTTON);
  11.                 UIPlayTween[] letsPlayTween = letsPlayGameObject.GetComponents<UIPlayTween> ();
  12.  
  13.                 Debug.Log (letsPlayTween [1].GetHashCode());
  14.                 EventDelegate.Add (letsPlayTween [1].onFinished, Fin);
  15.         }              
  16.                
  17.         public void close () {
  18.                 UnityEngine.Object.Destroy(lobbyGameObject);
  19.         }
  20.  
  21.         public void Fin () {
  22.                 close ();
  23.                 start ();
  24.         }
  25. }
  26.  

My intention is to keep the things in memory which i really need. I dont create and destroy the lobby endless times. Sometimes its better to
destroy and renew anything instead of resetting a lot of states.

Btw. This code snippet ist just a reduction to a minimum of the real code.
Thanks.

greetz retn

Title: Re: EventDelegate causing infinite loop
Post by: retn on July 09, 2014, 10:48:03 AM
Still causing problems....

Why is this code snippet causing an infinite loop?


  1. public class ngui {
  2.  
  3.     private GameObject lobbyGameObject;
  4.  
  5.     public void start () {
  6.         // instanciate new gui nui root
  7.         GameObject g1 = Resources.Load ("Gui/Lobby/Lobby") as GameObject;
  8.         lobbyGameObject = GameObject.Instantiate (g1) as GameObject;   
  9.  
  10.         GameObject letsPlayGameObject = GameObject.FindWithTag (TagManager.GUI_LOBBY_LETSPLAY_BUTTON);
  11.         UIPlayTween[] letsPlayTween = letsPlayGameObject.GetComponents<UIPlayTween> ();
  12.  
  13.         Debug.Log (letsPlayTween [1].GetHashCode());
  14.         EventDelegate.Add (letsPlayTween [1].onFinished, Fin);
  15.     }          
  16.        
  17.     public void close () {
  18.         UnityEngine.Object.Destroy(lobbyGameObject);
  19.     }
  20.  
  21.     public void Fin () {
  22.         close ();
  23.         ngui m = new ngui();
  24.         m.start();
  25.     }
  26. }
  27.  

When i start a new instance of my ngui class and call start.. it MUST work! But why not? It looks like the delegate is executed by adding an event.
greetz
Title: Re: EventDelegate causing infinite loop
Post by: ArenMook on July 09, 2014, 03:37:05 PM
Look at what happens inside your "ngui" class. From the code you posted, you're simply triggering a function when the tween finishes. That's it. When in doubt, always examine the call stack by checking the log. It will tell you why the problem occurred by giving you an idea of where it happened.

Also, never use Instantiate with UI. Use NGUITools.AddChild.
Title: Re: EventDelegate causing infinite loop
Post by: retn on July 12, 2014, 05:21:52 AM
Hey ArenMook,

thanks for your reply. Even if i use NGUITools.AddChild i run into an infinite loop. If i use a prefab and put it into the scene or i instantiate it like this, it doesnt matter.

If i have a new instance of a gui and i add an event, it may not be executed or may not run into an infinite loop. Its a bug in the NGUI framework. Take it or leave it. I paid for this framework. I wanna help to make it better. In my opinion its not usability. Best practise or not, it has to work.

Kind regards
retn


Title: Re: EventDelegate causing infinite loop
Post by: ArenMook on July 12, 2014, 04:19:03 PM
Well, let's run through the logic.

ngui.start():
1. New object gets created. Where is it created? It must be added to your UI root somewhere. Assuming you changed Instantiate to NGUITools.AddChild(parent, child) this will be resolved.
2. You search for a game object using its tag. What has this tag? I'm going to assume it's some object in the prefab you instantiated.
3. You get the tween on that object from #2 and add an OnFinished listener to it.
4. I'm assuming the tween is not disabled on your prefab, so it will start playing now.
5. The tween gets to the end, Fin() gets called. You are now calling close(), which destroys the game object.
6. You now start a new class, and everything begins again from #1.

Here's one problem. When you call Destroy(gameObject), the object does not get destroyed right away. The second time your function runs, your GameObject.FindWithTag is likely going to find the first instance, not the second one. This is one of many reasons why GameObject.Find is a terrible practice. You instantiated an object. Shouldn't you at the very least search for a child of that instance, not globally?

Second problem... you keep instantiating and deleting objects over and over. Why not re-use the same one? You could simply set the tween to loop. Why not do that? Why create a brand-new menu every time the old one finishes tweening?

Another issue... why do you rely on the order in which tweens will appear in the list returned by GetComponents<UIPlayTween>? Why do you assume that the tween you want is always going to be the first one?
Title: Re: EventDelegate causing infinite loop
Post by: Nicki on July 12, 2014, 04:45:33 PM
It's a consequence of how Unity works. You were using it wrong.

It's like saying
  1. while (true){}
causes an endless loop, fix it, Unity!


Anyways, a solution to your troubles could be to put a component on your Lobby prefab that references your LetsPlayButton's UIPlayTween and grab it with a GetComponent from the lobbyobject you instantiate.
Title: Re: EventDelegate causing infinite loop
Post by: retn on July 13, 2014, 01:55:26 PM
Huiuiui...

Thanks for reply. I dont wanna talk about that anymore. In my opinion its senseless.

@Mook
1. The Tween is not active. Its a button which triggers the tween. Even if its triggered, it should spam the scene not
causing an infinite loop. The tween has a time of 5 second and i can fire the button once!
2. Destroy, Instantiate and Find will work in a row in the next frame.
3. A new instance means also a new separate eventqueue.

@Nicki
The GetComponent thing is a good idea but it works with FindWithTag as well.

Maybe i should desribe it more detailed. The lobby has 3 buttons. Any button forces a tween. The tween moves the container outside the viewport. So if i have a new ui instance, i just put the delegate on the tween object, which is not  triggered automatically. By pressing the Button, the tween is activated and the roll goes on.

My code works like a cham without the eventdelegate method. Its not a fault in my code. I have a lot experience in such projects and i know how unity works.

Thanks for your help anyway. I have to reference it in scene diretly. Well.... Thats what it made for i think.

ciao