1
\$\begingroup\$

I want to avoid check if a particular function is returning true, and perform an action (Set Active) once it does return true for the first time.

Currently my code looks like this:

Update() {    
    if ( IsTaskCompleted() ) {    
        object.SetActive( true );
    }
}

SetActive gets called every frame after the task is completed. How can I avoid this, and call SetActive only once?

\$\endgroup\$
  • \$\begingroup\$ So you only want to execute it the first time when the task was completed? \$\endgroup\$ – Philipp Aug 4 '17 at 13:58
  • \$\begingroup\$ yaa, exactly!!! \$\endgroup\$ – MrRobot9 Aug 4 '17 at 13:59
  • 4
    \$\begingroup\$ Well you should read up about the wonderful world of events. \$\endgroup\$ – Uri Popov Aug 4 '17 at 14:00
  • \$\begingroup\$ Start using C# events or UnityEvents \$\endgroup\$ – Sidar Aug 4 '17 at 15:29
4
\$\begingroup\$

Create a flag which says if there is a pending task:

class TaskListener : MonoBehaviour {

    private bool taskIsRunning = false; // set to true when you start the task

    Update(){

        if (taskIsRunning && IsTaskCompleted()){
           taskIsRunning = false;
           gameObject.SetActive(true);
        }

    }

    //...

Another option is to make the task itself aware of which objects need to be activated when it's finished and make that a part of the task.

When the task can't know which objects it needs to notify at its end, you could also use an Unity Broadcast Message to call a specific method on every script which has it in a specific branch of your scene tree. But keep in mind that this isn't very fast, especially when you have a large branch.

Or you could use the Unity Event System. Have the task trigger a custom event when it's finished and have each script which is supposed to react on that event implement a custom event handler interface.

\$\endgroup\$
3
\$\begingroup\$

If you don't want to use events, this is pretty simple to solve with a coroutine (a function that can span multiple frames). You just add your "cleanup" code at the end of the function. Just make sure to call the function using "StartCoroutine()" instead of a standard function call.

IEnumerator MyTask(){
    //Do task here
    //You may need a different kind of yield return depending on the type of task.
    yield return null; 
    //Cleanup code goes here
    object.SetActive(true);
}

This way you're avoiding a (usually) useless conditional statement in Update. here's the unity doc for coroutines for further reading.

https://docs.unity3d.com/Manual/Coroutines.html

\$\endgroup\$
  • 2
    \$\begingroup\$ You probably don't want to activate gameObject here - that's the name used for "this" game object that the script is running on. If it wasn't already active, our Update and coroutine methods wouldn't be getting called/stepped by the engine, so this code wouldn't run. It looks like OP is referencing some other GameObject called object \$\endgroup\$ – DMGregory Aug 4 '17 at 15:47
  • \$\begingroup\$ Oh good call, I misread his code - Fixed. \$\endgroup\$ – Zebraman Aug 4 '17 at 16:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.