help with recursive code

hello,

i am trying to create a prediction system which wont take too much of the CPU,

i have seen and attempted other code, but it raises the cpu time from 5 ms to 600ms… this is not good…

so im trying to fix that with this code…

the issue is that i have a recursive point in the code in which a function starts the sequece of other functions including itself… but when i do so unity stops working… obviously there is something that is missing to make this work…

here is the code:

void Update() //possibly change to Fixedupdate later
    {  
        if(!cueInstantiator.getCueAvailable())
        {
            startedShowTrajectory = false;
            return;
        }

        unitVector = cueRotationManager.getUnitVector();
        cueStrength = cueRotationManager.getCueStrength();
        positionToHit = cueRotationManager.getPositionToHit();

        if(!cueRotationManager.getCueManagerActive())
        {
            force = (-1)*unitVector*DEFAULT_FORCE;
        }
        else
        {
            force = (-1)*unitVector*cueStrength;
        }
       
        if(startedShowTrajectory)
        {
        return;      
        }
        ShowTrajectory();
        startedShowTrajectory = true;
    }

    void CreateMovementMarkers()
    {
        if(i % interval == 0)
        {
        GameObject g = GameObject.Instantiate(marker, ball[0].transform.position, Quaternion.identity);
        markers.Add(g);
        SceneManager.MoveGameObjectToScene(g, SceneManager.GetSceneByBuildIndex(1));
        }
    }
   
    void ShowTrajectory()
    {
        if(!cueInstantiator.getCueAvailable())
        {
            return;
        }
       
        SyncBalls();
    }

    void SyncBalls()
    {
        for(int i = 0; i <= 15; i++)
        {
        ballRB[i].velocity = Vector3.zero;
        ballRB[i].angularVelocity = Vector3.zero;
        ball[i].transform.position = originalBall[i].transform.position;
        ball[i].transform.rotation = originalBall[i].transform.rotation;  
        }
        MoveForwardInTime();
    }

    void MoveForwardInTime()
    {
        ballRB[0].AddForceAtPosition(force, positionToHit, ForceMode.Impulse);
        for(i = 0; i < stepsToMoveForward; i++)
        {
            scene.GetPhysicsScene().Simulate(Time.fixedDeltaTime);
            CreateMovementMarkers();
        }
       
        i = 0;
        ClearTrajectory();
        //ShowTrajectory();
    }
   
    void ClearTrajectory()
    {
        foreach(var GO in markers)
        {
            Destroy(GO);
        }
        markers.Clear();
    }

the error starts at the end of the MoveForwardInTime() function where i commented out the issue… it works now becuase it is not recursive now… although when i uncomment it out it will cause unity to stop working…

i would like the commented out function to be part of the code and to be at that position because i want the code to update itself whenever it finishes… which is that point in the code…

Whenever you have a recursive process there always needs to be a condition in which the recursion terminates. The only place I can see that will stop it is in ShowTrajectory when you call if(!cueInstantiator.getCueAvailable()), so make sure that getCueAvailable() is returning false when it’s supposed to.

Hey thanks for the answer. U are correct that the if function is the only place where the function can stop. The thing is that I want the function to continue recursivly while getCueAvailable true… but I dont see why it would cause unity to stop working because each function is called when the next is complete so I dont see an overload or something…

Is it possible that a coroutine is needed to make it work?

Sure, but when is getCueAvailable ever true? Remember that when your recursive function loop is running, there’s nothing else happening unless maybe you’re doing something on a separate thread or a server.

1 Like

Since your functions are all calling each other in a circle, you could probably improve performance (and possibly avoid a crash in certain extreme cases) by switching from recursion to a loop.

Right now, each of your functions is remaining on the call stack even when it is “finished”, because technically it’s not finished until all the functions it calls have also finished, and so each time around this circle is adding another 3 layers to the call stack that can’t be popped until the very end when the loop terminates.

Since the recursive calls are the last thing that each function does, the compiler could theoretically optimize the recursion to avoid this accumulation of call stack layers. Some languages do this (it’s commonly called “tail recursion”), but IIRC the C# compiler does not, so you’re getting stuck with that overhead.

But in this case, it would be pretty easy to refactor your code to get around it, by replacing your recursive calls with something like this:

void ShowTrajectory()
{
    while (cueInstantiator.getCueAvailable())
    {
        SyncBalls();
        MoveForwardInTime();
        ClearTrajectory();
    }
}

Now, there is still a question of whether this loop ever terminates at all. It’s not clear from what you’ve posted what the actual end condition is, but it looks like you’re doing a bunch of physics, and computational physics is notorious for giving unpredictable results, so if you are counting on the physics engine to nicely “settle down” that might be your problem.

Also note that you aren’t allowing the main game loop to run at all while you’re doing this, which means you won’t be able to see any of the physics that is happening or receive any user input.

If you’re not 100% sure that your loop is going to terminate, it’s often a good idea to add in a safeguard that forcibly terminates it after some limit. e.g.

void ShowTrajectory()
{
    const int maxIterations = 1000;
    for (int i = 0; i < maxIterations && cueInstantiator.getCueAvailable(); ++i)
    {
        SyncBalls();
        MoveForwardInTime();
        ClearTrajectory();
    }
}

That forces the loop to “give up” if it runs too long without reaching the normal termination condition.

1 Like

thanks you for the comments… here my code stops running when i take a shot… it that centario, the cuestick is destroyed and becomes null in another script at getcueavailable is thus false.

It is extremely unclear what “take a shot” means in technical terms, but if this is some kind of user action, it’s probably impossible, because you are blocking the main game loop. Time isn’t passing, the screen isn’t drawing, Update is not being called, etc.

this is a seperate physics scene, so it recieves from the default in which it is on autoSimulation…

what do you mean by blocking the main loop?

for clarity, if i could take you through my logic for the script…

first of all, i have 2 scenes. one where the game is played and a second physics scene where an invisible simulation is attempted to take place (what i am trying to do)…

all of the booleans and floats and vectors are take from other scripts in which, i think if i am not mistaken, are running on autoSimulation… unlike the 2nd physics scene where i intened to move the simulation forward in time create movement markers every so frame and then set the simulation to zero, and all the positions of all the balls to where they correspond in the main scene and resart the process… and then keep on repeating the process as if i can get an infinite amount of different simulations… … this may happen forever but obviously a player action will take place which it will stop the code from running (getCueAvailable()) …

the 2nd scene only has what is needed the balls and the table, but is linked to the main scene…
all this is fine and working. i presume, as i have tested it and seems to be so…

now to describe the script…

my thoughts on this was to start the function from update() but not allow it to continously be called from there, since in my mind update is called 60 times per second and my loop should take around 2 seconds to complete… (time i want to predict) so i see that the update is pushing too hard on the function and that is why the ms jump to 700 from 5 ms as i stated in the first post…

so i decided to only do one call from the update… and have the process start…

first i start by updating the positions of the balls and velocities.

second i give a force to the imaginary cue ball and then move it forward in time… with every (interval) iteration of this i create a movement marker… which is rendered to the screen…

once the iterations have finshed it exits that loop (inside the MoveForwardInTime() function) clears the balls restarts their positions and then calls ShowTrajectory and does the process Once again.

this happens untill the cue is destroyed in the main scene… in which time is moving and is playable…
automatically when the balls in the main scene stop moving a new cue stick is generated and in return in this script update starts the process only once and the recursivness continues this…

now i see how this might add in the callStack and this i think is the problem since as Antistone stated that they are unloaded from the stack only after the function finished, but since every function is called in every other function, when do they finish?

i tried the while loop that Antistone posted. it had the same effect… the game did not start…

im going to try a few more stuff including a coroutine…

if anyone has any thoughts on this, please post whether it be my logic or my execution of said logic…

Most game engines (including Unity) work on the premise that the core part of the game is a loop that basically says:

  • Update the status of everything that’s happening in the game

  • Draw a picture of how things look now

  • Repeat

Each iteration of that loop is one “frame” of the game. Almost everything that happens in the game is ultimately called from this loop. (There are a few exceptions, like audio, but this loop is responsible for almost everything.)

One of the many, many things that happens as part of “update the status of everything” is that Unity iterates over all the MonoBehaviours in your game and calls Update() on each of them, one at a time. That means that until your Update function finishes and returns, nothing else can update. Unity is waiting for you to finish.

Your Update function calls ShowTrajectory. That means your Update function isn’t “finished” until ShowTrajectory is also finished, which doesn’t happen until your circular recursion loop stops.

Unity can’t continue with the main loop because it is waiting for you. Update is not called on any other objects, no new frames get drawn to the screen, the value of Time.time does not change, the game can’t respond to mouse clicks or key presses or anything. It’s all on hold because Unity is waiting for you.

thanks for the clarification…

i changed the initial function call in the update to
InvokeRepeating(“ShowTrajectory”, 0.1f, 3f);

and took out the recursive nature of the code.

it works now… thanks