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
1
Question by SirGive · Mar 07, 2012 at 05:39 PM · coroutineevent

Adding a coroutine to an event?

Is it possible to add a coroutine to an event? I'm experimenting with events, and it seems like it would be extremely useful. However, I've got to run a coroutine for one of the functions that will be assigned to the event. Don't know if I'm explaining this correctly so here's some code:

Event declaration:

 public delegate void BookSelectEventHandler();
 public static event BookSelectEventHandler BookSelect;
 public static void OnBookSelect()
 {
     BookSelectEventHandler bookSelect = BookSelect;
     if (bookSelect != null)
         bookSelect();
 }

Basically what I want to do (but not a solution):

 BookSelect += StartCoroutine(RenderWholeBook);

My function:

 IEnumerator RenderWholeBook()
     {
                     //snap
         yield return null;  //return next frame
                     //change text
         yield return null;  //return next frame
                     //snap next page
         yield return null;  //return next frame
                     //turn off
         yield break;
     }

Is this even a viable approach? Or should I just do the long work around of reference and call the function?

Also thought about this:

 public delegate void BookSelectEventHandler();
 public static event BookSelectEventHandler BookSelect;
 public static void OnBookSelect()
 {
     BookSelectEventHandler bookSelect = BookSelect;
     if (bookSelect != null)
         StartCoroutine(bookSelect());
 }

But it doesn't work either.

Comment
Add comment
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

6 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by SirGive · Mar 07, 2012 at 07:35 PM

Surprising simple:

 public delegate IEnumerator BookSelectEventHandler();
 public static event BookSelectEventHandler BookSelect;
 public void OnBookSelect()
 {
     BookSelectEventHandler bookSelect = BookSelect;
     if (bookSelect != null)
         StartCoroutine(bookSelect());
 }
 

And you can only add functions with the return type of IEnumerator:

  • Only the last event handler to be added will be called -- Luiz

  • only use one, so it works for me*

And this is how you would add the function to the event:

 BookSelect += RenderWholeBook;

Updated my answer. Everything works perfectly.

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 mgsteinkamp · Dec 24, 2015 at 03:12 AM 1
Share

Can you remove that "everything works perfectly" part? Only the last event handler added runs, so it's far from perfect...

avatar image
2

Answer by luizgpa · Mar 07, 2012 at 07:41 PM

I'm not sure what your intentions are, but you can't start a directly coroutine from a static method since StartCoroutine is a member method from MonoBehaviour. Another problem is that the event handlers must be a coroutine, so they must return IEnumerator.

 public delegate IEnumerator BookSelectEventHandler();
 public static event BookSelectEventHandler BookSelect;
 public void OnBookSelect()
 {
     if (BookSelect != null)
         StartCoroutine(BookSelect());
 }

 static IEnumerator RenderWholeBook()
 {
                 //snap
     yield return null;  //return next frame
                 //change text
     yield return null;  //return next frame
                 //snap next page
     yield return null;  //return next frame
                 //turn off
     yield break;
 }
 
 (...)
 
 BookSelect += RenderWholeBook;

However there's a problem: only the last handler is called.

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 SirGive · Mar 07, 2012 at 08:15 PM 0
Share

So the last function added would be the only one to ever be called? That would defeat the purpose of using events wouldn't it?

avatar image
1

Answer by Syganek · Aug 17, 2017 at 10:48 AM

I know it's few years since question was asked but I had similiar problem.

My solution was to simply invoke every delegate manually.

 public delegate IEnumerator PlannedActionsEventHandler();
 
 private PlannedActionsEventHandler _plannedActions;
 
 public void RegisterAction(PlannedActionsEventHandler plannedAction)
 {
     _plannedActions += plannedAction;
 }
 
 private IEnumerator InvokeActions()
 {
     if (_plannedActions != null)
     {
         //Invokes all planned actions and waits until they're done.
         foreach (var @delegate in _plannedActions.GetInvocationList())
         {
             yield return @delegate.DynamicInvoke();
         }
     }
 }

Please let me know if they're any problems with this method.

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 abertrand · Jan 31, 2018 at 09:51 AM 0
Share

This is the only correct answer in this thread. Alternatively even simpler:

  public event Func<IEnumerator> coroutineOnEvents;
  
  OnEnable()
  {
      coroutineOnEvents += DoStuff;
      coroutineOnEvents += DoStuff;
  }
  
  private IEnumerator InvokeActions()
  {
      if (coroutineOnEvents != null)
      {
          //This will play DoStuff twice
          foreach (var @delegate in coroutineOnEvents.GetInvocationList())
          {
              yield return @delegate.DynamicInvoke();
          }
      }
  }

  private IEnumerator DoStuff()
  {
      yield return null;
  }

avatar image
0

Answer by Berenger · Mar 07, 2012 at 07:30 PM

Your delegate needs to return an IEnumerator, as well as BookSelect's function, which is probably assigned from elsewhere. Then, you call StartCoroutine(bookSelect());

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 $$anonymous$$ · Nov 23, 2013 at 12:12 AM

You can get past this with one more level of functionality.I actually hit the same problem //delegate public delegate void BookSelectEventHandler(); //event public event BookSelectEventHandler BookSelect; //Trigger Event Function public void OnBookSelect() { if (BookSelect != null) BookSelect(); }

 //The function we want to run as a coroutine
 IEnumerator RenderWholeBook()
     {
     //snap
     yield return null; //return next frame
     //change text
     yield return null; //return next frame
     //snap next page
     yield return null; //return next frame
     //turn off
     yield break;
     }
 //Helper function that gets registered on the event and //calls the actual function we want to run as a coroutine //without waiting for it.
 public void HelperFunction(){
     StartCoroutine(RenderWholeBook);
 }
     (...)
 //In a Start/Awake/OnEnable/WhateverEventRegistering code //you use
     BookSelect += HelperFunction;

This way when you register listeners to the BookSelect event they won't be IEnumerators and won't stumble on the restriction of just using the last listener/handler whatever you want to call it.

The problem is when you want to wait for the coroutine to finish....if you do then you can't use a helper function because you'd need to yield return the RenderWholeBook which means you have to declare whatever function is going to call the "yield return ...." piece of code.Which is kind of a chain reaction towards the parent function. Calling StartCoroutine creates the coroutine and exits.Which means that if you need info about this you have to pass them through arguments.

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
  • 1
  • 2
  • ›

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

10 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

Related Questions

Rerun a script after it finishes, when it already has multiple Coroutines? 1 Answer

How to change this using a coroutine 1 Answer

Ienumerator wait for event 0 Answers

Waiting for and using output of a UnityEvent within coroutines 1 Answer

Best way to wait for event inside Coroutine? 3 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