- Home /
Static recursive function syncing?
Is there anyway I could make a static recursive function call itself in sync with Unity's Update cycles?
Edit: Heres a code example of roughly what I was trying todo. I've now found out it's a bad idea. See comments from @Statement and @Bunny83 for reasons.
public static class Manager
{
private Boolean _enabled = false;
public Boolean Enabled
{
set{
if (value== true)
{
Start();
}
else
{
Stop();
}
_enabled = value;
}
}
public void Start(
{
enabled = true;
DoSomething();
}
public void Stop()
{
enabled = false;
}
private void DoSomething()
{
if(enabled)
{
//Do somthing on GameObjects.......
//Recurse - ** WANT TO SYNC THIS CALL WITH UNITY UPDATE CYCLES **
DoSomething();
}
}
}
Generally recursive calls are considered bad, and eat up stack memory like no tomorrow. Coupled with Coroutines it sounds like a bad idea. What is it that you are trying to solve really?
I'm not a great programmer so could you elaborate on the memory issue? I thought it would be know different to calling a function at a set interval!
Recursive calls need to keep track of the variables and call stack so it can exit them when they are done. $$anonymous$$ost recursive functions can be implemented with a Stack or List and be run in a loop ins$$anonymous$$d. To call a function at a set interval you could use InvokeRepeating, or just have a Coroutine that goes into a loop, with a yield return null; (C#) or yield; (JS) at the end of the loop. For example, the following code might suit your needs depending on what it really is you want to do...
void Start() {
StartCoroutine(Example());
}
public static IEnumerator Example() {
for (int i = 0; i < 60; ++i) {
Debug.Log("Frame #" + i);
yield return null;
}
}
I was more thinking of implementing it in a normal class that doesn't inherit from anything, not a monobehaviour. Sorry I'm terrible at explaining things. I'll ask again when I remember exactly what I wanted it for. Sorry if you feel like I've wasted your time.
I think i got what you want to do. The problem is that Unitys scripting environment runs in a single thread. Coroutines are a nice "trick" to implement some kind of cooperative multitasking inside this single thread. The object that represents the coroutine have to be attached to a $$anonymous$$onoBehaviour class because that's the interface that Unity offers.
Almost everything that can interact with Unity is stored in a GameObject. That's one of the great advantages of Unity. Unity keeps the whole system very simple. There aren't hundreds of different classes you have to deal with.
You still can start a seperate thread that runs beside Unitys scripting thread, but in this case you can't interact with the Unity API because it's not thread-safe.
The problem with recursive functions is that every time you call a function, the system creates a stack-frame and stores the return address where it should continue when the function is completed. A recursion without an exit condition will fill your whole stack within a fraction of a second and the application gets ter$$anonymous$$ated due to stack-overflow.
A recursion will create a chain of function-calls. Each function-call is not finished before before the function call inside the function has returned but since every called function calls the function again it will never end. At the moment the innerst function call returns the chain resolves in reversed order. Take a look at my example. The Debug.Log at the end of the function is called when the exit condition is true. All those "$$anonymous$$yRecursion End" logs will show up in the same frame it reaches the end-condition.
Answer by Statement · Aug 13, 2011 at 07:12 PM
Not quite sure what you mean, but I'll give my best shot at it.
void Example()
{
StartCoroutine(Recursive(this, 10));
}
static IEnumerator Recursive(MonoBehaviour s, int value)
{
if (value <= 0) yield break; // Will exit the coroutine
yield return null; // Wait for next frame
// Do any processing if you wish, then call recursively again using g.
Debug.Log(value, s);
yield return s.StartCoroutine(Recursive(s, value - 1));
}
Well, i totally forgot the "static" in the quesiton :)
StartCoroutine is not a member of GameObject. It's a member of $$anonymous$$onoBehaviour so you need to pass one to the function. ("this" will do :D)
Thanks I appreciate both your answers. I can't exactly remember what I need to implement it for which is a bit embarrassing but basically it was due to the fact that there are times where you don't want to have implement functionality into components that have that have to be attached to objects and added to the scene. The static recursive function would hopefully eli$$anonymous$$ation the need to use singletons. Seeing as both of your solutions use coroutines I'm assu$$anonymous$$g there is no other way. Is that can be accessed that will tell me the fixed frame rate?
Answer by Bunny83 · Aug 13, 2011 at 07:17 PM
That doesn't make much sense. Recursive functions need a termination-condition since each recursion will consume memory which is freed when the whole recursion is finished. Even when you use coroutines to "sync" with Update you will have the same problem.
If you have a well planed recursion (with exitcondition) just turn it into a coroutine and do a yield;
(Unityscript) or yield return null;
(C#) to wait for the next frame.
static function MyRecursion(script : MonoBehaviour, value : int) { Debug.Log("MyRecursion Start :" + value); yield; if (value > 0) { yield script.StartCoroutine(MyRecursion(value - 1)); } Debug.Log("MyRecursion End :" + value); }
function Start() { MyRecursion(this,3); }
This will run one recursion each frame and the output should look like this:
MyRecursion Start :3 // frame 1
MyRecursion Start :2 // frame 2
MyRecursion Start :1 // frame 3
MyRecursion Start :0 // frame 4
MyRecursion End :0 // all returns will also happen in the frame 4
MyRecursion End :1 // ..
MyRecursion End :2 // ..
MyRecursion End :3 // ..
(This script has not been tested yet!)
Your answer
Follow this Question
Related Questions
Code isn't Recursive in update? 2 Answers
I need a way to run code much more frequently than update. Ideally, every 3 milliseconds 2 Answers
How do I Instantiate a prefab to touch and still update a score? 1 Answer
Is there a scene setup call or update for editor scripts? 3 Answers
What process should I best use to properly create an updated copy of a Prefab? 1 Answer