Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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
2
Question by AlecGamble · Apr 26, 2017 at 09:56 AM · variablecoroutinedelegate

Pass delegate to coroutine as a variable

Hi guys,

I want to be able to add various behaviours to my player from various triggers. I figured the best way to do this would be through the use of delegates. I want to be able to externally trigger adding a delegate to the player for a duration. For Example:

  • Player walks on reverse direction item

  • Reverse direction item gets a reference to the player and adds a "ReverseDirection()" method to the OnMovement delegate

  • After a duration the reverse direction effect wears off

I would imagine being able to do something like that like this:

     public delegate void PlayerBehaviour();
     public MissileBehaviour onMovementBehaviour;
 
     public void InvertMovement()
     {
         moveDir *= -1;
     }
 
     public void AddBehaviour(PlayerBehaviour behaviour, System.Action method, float duration = 0f)
     {
         StartCoroutine(AddBehaviourEnumerator(behaviour, method, duration));
     }
 
     IEnumerator AddBehaviourEnumerator(ref System.Action behaviour, System.Action method, float duration)
     {
         behaviour += method;
         if(duration == 0f) return;
         yield return new WaitForSeconds(duration);
         behaviour -= method;
     }

and then I could add the behaviour externally like so

     Player p = playerObject.GetComponent<Player>();
     p.AddBehaviour(p.onMovementBehaviour, p.InvertMovement, 5f);

but the issue is that I can't pass a ref to a coroutine so I'm not quite sure how to pass the delegate as a variable to make this work.

Any help would be appreciated. Thanks!

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

1 Reply

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

Answer by Bunny83 · Apr 26, 2017 at 10:29 AM

That's completely impossible. ref parameters actually use pointers to the actual memory location where the variable is stored. That's why you can not "store" the content of a ref parameter in another variable for later use. It's only valid within the current chain of execution.

A coroutine is not a method but a class instance which you create when you invoke the coroutine. The coroutine scheduler of Unity handles the scheduling of the coroutine when necessary.

The parameters to a coroutine / iterator function are translated into member variables of the hidden auto generated state machine class that the compiler generates out of your coroutine / iterator. However since we can't "store" ref parameters in variables, ref parameters are not allowed at all in iterator functions / coroutines.

What you can do, however, is handling the adding / subtracting in a closure:

 IEnumerator AddBehaviourEnumerator(System.Action aBefore, System.Action aAfter, float duration)
 {
     aBefore();
     if(duration == 0f) return;
     yield return new WaitForSeconds(duration);
     aAfter();
 }

And call it like this:

 p.AddBehaviour(()=>p.onMovementBehaviour+= p.InvertMovement,()=>p.onMovementBehaviour-= p.InvertMovement , 5f);

Closures work completely different. They may create a closure class that will house the actual variable. Every bit of code that accesses the variable will be changed to use the closure class instance. Since this is just an ordinary class, it can be stored inside the closure and allows access to the variable.

Another way is to create a wrapper object for your delegate that includes the coroutine method:

 [System.Serializable]
 public class DelegateWrapper
 {
     public System.Action onDelegate;
     public IEnumerator AddBehaviour(System.Action aCallback, float aDuration)
     {
         onDelegate += aCallback;
         if (aDuration == 0f) yield break;
         yield return new WaitForSeconds(aDuration);
         onDelegate -= aCallback;
     }
 }

So when declaring your event you would use the wrapper instead:

 public DelegateWrapper onYourEvent;

You could implement the + and - operators in the wrapper so you could use the wrapper almost like a normal delegate.

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 AlecGamble · Apr 26, 2017 at 10:51 AM 0
Share

This looks amazing, exactly what I was looking for! Thank you! (I'll mark as accepted once I've implemented it).

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

72 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 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 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

How to get a variable out of a coroutine? 3 Answers

Start a Coroutine with a delegate that has a parameter 1 Answer

How to use a float value from coroutine 1 and use in coroutine 2? 1 Answer

How Return Or Restart A Coroutine When A Variable Increase? 0 Answers

How Return Or Restart A Coroutine When A Variable Increase? 1 Answer


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