Call a function from within itself

Okay i'll try to explain what i'm doing first because maybe i'm approaching this the wrong way.

I have a function called playSound() which is itself called by either an animation event, through some action by the player (pressing a button for example), or - not yet implemented - called in an object's Start() function.

The playSound() function in turn is responsible for playing a sound and calling another function, on another script, called playAnim(). This function cycles through the textures of the GUITexture on the object it is attached to, and also hides the guiTexture if the player is not within range.

It works fine at the moment because the animation events are fired once every so often. However, with player input or the Start() function, I need the sound effect to keep playing and the guiTexture to keep animating. Moving them into Update() functions hasn't helped, either because the music stutters (I can add an if statement to fix that) or the guiTexture is replaced too rapidly.

My code is becoming a bit unruly now so I am trying to keep everything in three separate functions: sound, animation, and what will be particle systems. I want to keep my existing animation script which works with one time events, so i'm now trying to add a boolean that reruns the function if it is set to loop. From what i've read, this is called recursion, but I can't get the syntax right. I've also read about InvokeRepeating and CoRoutines but i'm not sure how i'd use them here. I just need the function to repeat, not delay. I tried something along the lines of:

function PlayAnim() {

    // loop through guiTextures here

    // check if this animation has been set to loop
    if(isLooped){
        PlayAnim();

    } else {
        guiTexture.enabled = false;
    }
}

But I get an error "..type could not be resolved because of a cycle. Explicitly declare the type of either one to break the cycle." Here's a diagram to illustrate what i've discussed:

Animation Event            Player input               Start function
     |___________________       |        ________________|
                         |_ _ _ |_ _ _ _| 
                        |                |
                        |   playSound()  |<----
                        |_ _ _ _ _ _ _ _ |    |
                 __________|   |              |
                |              |              |
        _ _ _ _ |_       _ _ _ | _ _ _ _ _    |
       |           |    |                 |   |
       | playAnim()|    | Particle Effect |   |
       |_ _ _ _ _ _|    |_ _ _ _ _ _ _ _ _|   |
                |                     |       |
                |_______isLooped?_____|_______|

I had the same problem. In order to call a recursive function, you have to return the type IEnumerator.

Edit: This tread has been answered by now, but I am correcting my post in case someone else stumbles upon it. Like Eric said in the comment, you can return any type that is appropriate, but the compiler logs an error if you do not explicitly declare the return type.

I don't think recursion is a good fit for this problem at all. It sounds like you just need a simple repeating loop. Either actually set the audio source to 'loop', use a coroutine to wait for the duration of the audioclip, or use AudioSource.isPlaying to determine whether to retrigger the sound.

However, to me it sounds like you still need to think some more about the structure of what is going on here, and if you want help with that you might need to provide a better description of what you're trying to achieve in general.

The way you've written your question currently might prevent you from getting good solutions because you've omitted a "big picture" description of what you're actually trying to achieve. For example "I'm trying to make a repeating weapon with synchronised sound and firing animation", or "I want to make a virtual speaker which animates when music is playing", or something like that. That way, us problem-solvers will be able to see a broader picture and perhaps a good way of structuring your code. As it is, all we have to go on is an abstract description of the spring, nuts and bolts that you're trying to assemble, with no clear picture of the intention of your 'machine'. :)

Okay, i've managed to tidy up my code a lot and I don't anticipate another question on this thread, but i'll post my new script incase it helps anyone else/anyone wants to critique it. It's not going to win any awards for god-like coding skills, but it's an achievement i'm satisfied with.

As I said in the comments, i'm trying to create a system where system where various sound sources in the environment - a dripping shower, a running tap, a stereo playing - make a sound, show an animated graphic in the HUD, and play some in world animation such as a particle effect. Using animation events on an animated sphere, I was able to synchronise a dripping showerhead with an onscreen graphic, but I quickly realised that it would be quite time consuming to create dummy animations to synchronise with more complicated sounds. So instead i'm creating graphics that could represent the sound, even if they don't match up completely.

Most sounds in the environment are continuous (a generator humming), others play once invoked through player action (turning on a shower) and will continue to play until the player stops them. While a couple are special one-time events called from animation events (the dripping showerhead). Marrying all these types up for handling by one function proved a bit of a conundrum.

What i've now achieved is a system where most of the sounds are handled by one function (the non-animation event ones), while the animation event sounds are a special case, handled by a function in another script (keeping them separate to avoid problems with the update function). Both these scripts then call a third script which plays the relevant HUD animation. Below is the script i'm using for most sounds. It's a vast improvement on previous versions since it handles all three components - guiTexture, sound clip, and world animation. It also includes an isEnabled flag so that certain sounds can be triggered by the player in the game, while others I can set enabled from within the editor.

// gameObject for animation that plays in the world
var myWorldObj : GameObject;

// the assigned guiTexture to show the sound in the HUD
var myGUITex : GameObject;

// flag to determine when these sound/anims are allowed to play
var isEnabled : boolean = false;

function Update () {

    if(isEnabled){

        // call the function to show the GUI animation (runs once each time)
        if(!myGUITex.guiTexture.enabled){
            myGUITex.GetComponent("guiTexAnim").PlayAnim();
        }

        // turn on the object holding the world animation
        if(myWorldObj){
            myWorldObj.active = true;
        }

        // play the associated audio
        if(!audio.isPlaying){
                audio.Play();
        }

    } else {

        // turn off the object holding the world animation
        if(myWorldObj){
            myWorldObj.active = false;
        }

        // stop the audio
        if(audio.isPlaying){
            audio.Stop();
        }
    }
}

@script RequireComponent(AudioSource)

Note, I'm using the active property to disable objects at the moment, but i'm thinking I should use renderer.enabled instead if this is a better solution?

One little quirk I did find. I haven't created the model for the stereo yet so I used an empty object temporarily to place the sound source. However Unity wouldn't assign an AudioSource to the empty object, despite the last line in my script. I also tried adding an if statement to make sure all objects had an Audio Source before working with it, but Unity still ignored this for empty objects and gave me an error about no Audio Source being attached. Unity attaches an Audio Source no problem for primitives and imported models, and I can add an Audio Source to an empty through the Editor, so is this some bug related to adding one to empties through code?