- Home /
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?_____|_______|
Answer by duck · Apr 06, 2010 at 03:43 PM
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'. :)
Hi Duck, thanks for your advice. You're right, I'm was agonising over my structure last night, trying to keep it all straight in my head. Due to the problems I had trying to combine the one-shot sounds and repeating sounds, I ended up writing a separate script just for the repeating ones. I moved away from the recursion idea (a part of me thought it was a bad idea in general) and implemented AudioSource.isPlaying ins$$anonymous$$d to decide whether to allow a function to proceed. It's not a very elegant solution at the moment - I can see a lot of duplication - but i'll try to fix that this evening.
You're right about my original question, I didn't explain it very well at all. I was trying not to bore anyone with unnecessary details, but in doing so it does come across as very abstract. What i'm trying to create is a system where sound effects in the environment - a drip from a shower, a running shower, footsteps, a stero playing etc - show up in the HUD as an animated graphic, and in the world (where necessary) as something like a particle system (think of the stereo in The Sims). I've got the first part, the HUD, implemented. I don't feel my code is very efficient, but deadline looms=S
Answer by Peter G · Apr 06, 2010 at 01:21 AM
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.
You only need to return the type IEnumerator if that's actually appropriate. Recursive functions can be anything, including void.
Answer by straydogstrut · Apr 06, 2010 at 11:23 PM
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?
Your answer
![](https://koobas.hobune.stream/wayback/20220612145126im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Loop a function in c#.HELP!!! 2 Answers
Loop a function 1 Answer
while loop not looping 2 Answers
Loop a Function a Random Number of Times 2 Answers
first function dismiss 0 Answers