Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Catlard · Jun 05, 2014 at 05:03 PM · coroutineinstanceienumeratorvoidwrapper

Coroutine design problem?

So, let's say I want to start a coroutine that tweens a value from 0 to 1.

I start my coroutine. It is instance A. When the coroutine is half finished, and the value is tweened to .5, I want to start the coroutine again by calling it, and thus create instance B of he coroutine. BUT I don't want them to run at the same time -- I only want B to run now. I want to start afresh with B, and for A to have been stopped by StopCoroutine.

How do you do this elegantly, without calling a wrapper function that is void? I can't call StopCoroutine for a function WITHIN that function, and then move forward and run the new instance, correct?

EDIT: As a practical example, let's assume I have a class that manages the volume of an Audio Source -- the background music for a game. When the player gets a coin, I want to tween the volume of the music from .8 to .3, and then back up again, so the coin sound gets emphasis. The whole process of lowering and raising the music's volume takes, oh, say, 3 seconds. But let's say that the user gets two coins in 1.5 seconds. How does the music-dampening coroutine work that handles that? Currently, my approach is to have two functions, one of which is a public void function that always stops the private ienumerator function that does the tweening, and starts it again.

How do you handle this problem?

Comment
Add comment · Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Key_Less · Jun 05, 2014 at 07:46 PM 1
Share

I'm intrigued by your need to stop and then start the same coroutine based on a value. Can you give a little bit more detail on what you're trying to accomplish and why you need to stop the coroutine just to start it again? I have a solution for your issue but it may not be suitable, depending on what you're trying to do.

avatar image Catlard · Jun 06, 2014 at 10:40 AM 0
Share

Sure! I'll update my question with an example.

avatar image Tim-Michels · Jun 06, 2014 at 12:21 PM 1
Share

As far as I know, if you perform StopCoroutine inside your coroutine itsself, the original coroutine will keep running untill its next yield statement.

This means you should be able to do this without any problems. As long as there's not a yield between the following 2 lines.

StopCoroutine("coroutine");

StartCoroutine("coroutine");

avatar image gjf · Jun 06, 2014 at 02:06 PM 1
Share

perhaps you're overthinking the problem.

why not just assign a lower relative volume to the music ?

the player can always turn it up...

3 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by Key_Less · Jun 06, 2014 at 04:55 PM

What you're trying to achieve is sound ducking. I would recommend creating a script that holds a list of audio source references that need to "duck" when the audio source is playing.

So for example, you could attach the script to the game object that contains the coin audio source, and then add the audio source that contains the background music as a reference. This way, any time you play the coin sound clip, you could lower the volume for any audio clip references that need to duck their volume.

I'll try to demonstrate what I mean with a little bit of code:

 public List<AudioSource> SoundsToDuck;
 
 // Custom Play function
 public void PlayAudioClip()
 {
    DuckAudioClips(true);
    audio.Play();
    StopAllCoroutines();
    StartCoroutine(WaitForAudioToFinish(audio.clip.length));
 }

 /// <summary>
 /// This will loop through any audio source reference attached in the inspector
 /// and set their volumes depending on whether they are being ducked or unducked.
 /// </summary>
 private void DuckAudioClips(bool duck)
 {
    foreach (var clip in SoundsToDuck)
    {
       // If we want to duck the sound
       if(duck)
       {
          clip.volume = 0.3f;
       }
       else
       {
          // Unduck the sound. 
          clip.volume = 0.8f;
       }
    }
 }

 /// <summary>
 /// Use this to unduck the audio references once the audio 
 /// source this script is attached to has finished playing.
 /// </summary>
 private IEnumerator WaitForAudioToFinish(float delay)
 {
    // Yield for the amount of time it takes this audio clip to finish.
    yield return new WaitForSeconds(delay);
 
    // Unduck the sound clips.
    DuckAudioClips(false);
 }

I warn you, this is all untested. This approach could handle your issue with collecting several coins quickly, since the reference sounds will remain ducked as long as the coin audio clip is playing. However, this only sets the volume of the background music and does not fade it as you are intending to do, but hopefully this can still help and give you some more ideas.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Catlard · Jul 03, 2014 at 06:35 AM 0
Share

Hi, $$anonymous$$ey_Less! Thank you for your extremely thorough answer. This is exactly the approach I was taking when I wrote my sound player -- it does ducking just like this. But the problem is not necessarily that I have trouble ducking sounds -- it works fine. $$anonymous$$y question is about coroutines, and about stopping and starting them elegantly, or simply. It just seems odd that a person should need an extra coroutine wrapper -- the way your PlayAudioClip and WaitForAudioToFinish functions are seperate. These two lines solve the problem in your code:

  StopAllCoroutines();
    StartCoroutine(WaitForAudioToFinish(audio.clip.length));

And I use the same ones. But I feel like there must be a better way to do it. Don't you think there should? Or am I acting all crazytown again?

Cheers,

Simon

avatar image
0

Answer by aero80 · Jul 03, 2014 at 07:01 AM

You should check out

http://www.youtube.com/watch?v=VnbfEyL85kE Part 1 http://www.youtube.com/watch?v=Ex2td1En94Y Part 2

from Prime31. Basically he is writing a wrapper around coroutines which then you can pause, cancel...etc coroutines anytime you want. I think that will solve your problem.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by Andres-Fernandez · Jul 03, 2014 at 07:02 AM

Haven't tried, but I believe you can wait for another coroutine (from Unity Gems and from unity patterns). Call the same routine with one parameter to not call itself again if it's already nested. No wrapper needed.

 IEnumerator sameCoroutine(bool callSelf) {
    if (callself)
    yield return StartCoroutine(sameCoroutine(false));
 }


Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

24 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

OnCollisionEnter as IEnumerator problem (WaitForSecond) 2 Answers

Coroutine in C# and Question 2 Answers

Powerup issue - Speed 1 Answer

Coroutine error with result 1 Answer

Destroy Without A Collision Or Trigger 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges