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 Golan2781 · Dec 29, 2012 at 11:20 PM · coroutineyieldrepeatingcancel

how to restart coroutine on event?

I have a non-MonoBehavior class with some background functions that are supposed to wait for some time, then make a minor operation. A single component has several instances of that class, so I can't call invokeRepeating from the component (cannot access the individual instances' functions) nor the class itself (not a MonoBehaviour). Coroutines seem to be the most appropriate.
However, I need to be able to 'restart' the coroutine on a specific event, i.e. reset its delays. Any hints on how to do this from the outside or passively? Or can I only do this by explicitly checking the state every Update cycle?

In specific, my objects have several layers of health. Each layer can regenerate a full point of health every few seconds but if a layer receives damage, it looses the progress on regenerating the current new health point and must wait for a penalty delay before beginning the regeneration process anew.

 // start after receiving damage
 function regenerate () {
     // wait for damage penalty being done xor cancel and restart when receiving damage
     yield WaitForSeconds(attributes.regenDamageDelay); // <- need hook here
     while (true) {
         // wait a cycle xor cancel and restart when receiving damage
         yield WaitForSeconds(attributes.regenSecondsPerTick); // <- need hook here
         currentHealth++;
     }
 }
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

2 Replies

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

Answer by Golan2781 · Dec 30, 2012 at 11:30 AM

Okay, I got this working now with a mixture of the two: a coroutine carrying a timestamp of its own invocation and the parent class carrying a timestamp of the last invocation of its coroutine.

When the function gets invoked, it will set both the class timestamp and its own timestamp to be the same. Before each action, it will check whether the two are identical, i.e. if in the meantime another one was invoked. For robustness, the timestamp doesn't store the actual time but the order of invocation.
The stamp is big enough for 1000 invocations every second for about 1.5 months...

 class healthTest {
     var id : String;
     var health : int;
     var invokeStamp : uint;
     var timeInitial : float = 1;
     var timeRepeat : float = 2;
     
     function classCoroutine ( ) {
         invokeStamp++;    // store in the class when last this routine was invoked
         var initStamp : uint = invokeStamp;    // store in the routine when this specific routine instance was invoked
         Debug.Log('started coroutine');
         yield WaitForSeconds(timeInitial);
         if (invokeStamp!=initStamp) return;  // <- exit when not most current coroutine
         Debug.Log('finished initial delay @ ' + health + ' for ' + id);
         while ( true ) {
             yield WaitForSeconds(timeRepeat);
             if (invokeStamp!=initStamp) return;  // <- exit when not most current coroutine
             health++;    // <- do stuff when still alive
             Debug.Log('finished repeat delay @ ' + health + ' for ' + id);
         }
     }
 }

Note that this specific example is bound to a parent class. The example class is not derived from MonoBehaviour so it cannot invoke the coroutine, this is done by the parent class.

 // testComponent.js
 var regenDummy1 : healthTest;
 var regenDummy2 : healthTest;
 
 function Start () {
     regenDummy1.id='regenDummy1';
     regenDummy2.id='regenDummy2';
     regenDummy2.timeRepeat*=2;
     StartCoroutine(regenDummy1.classCoroutine());
     StartCoroutine(regenDummy2.classCoroutine());
 }
 
 function OnCollisionEnter(collision : Collision) {
     // 're'start the coroutines
     StartCoroutine(regenDummy1.classCoroutine());
     StartCoroutine(regenDummy2.classCoroutine());
 }
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
1

Answer by save · Dec 30, 2012 at 12:21 AM

If I understand you correctly you want to be able to break the cycle at any point. Using a condition for when the part receives damage and current elapsed time will let you do this. Set a boolean variable to true (called receivedDamage in example) when the part is taking damage, then yield one frame before you call Regenerate().

 private var receivedDamage : boolean = false;
     
 function Regenerate () {

     receivedDamage = false;

     //Do a time stamp
     var t : float = Time.time;
 
     //Use the time stamp as a condition
     while (Time.time<t+attributes.regenDamageDelay) {
         //Use another condition for when receiving damage to exit loop
         if (receivedDamage) return;
         yield;
     }
 
     //Set the condition to repeat while currentHealth is less than maxHealth and doesn't receive damage
     while (!receivedDamage && currentHealth<maxHealth) {
 
         //Do another time stamp
         t = Time.time;
 
         while (Time.time<t+attributes.regenSecondsPerTick) {
             if (receivedDamage) return;
             yield;
         }

         currentHealth++;
         yield;
     }
 }
Comment
Add comment · Show 2 · 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 Golan2781 · Dec 30, 2012 at 10:19 AM 0
Share

Yes, that's the 'long' version of what I want to do. I was hoping to get it done without the need to do all the timestamping and constant loops, coroutines make for much cleaner code - not to mention better performance as far as I know.

Still, if it's not possible to be done with coroutines, I think your answer is the way to go.

avatar image Golan2781 · Dec 30, 2012 at 11:32 AM 0
Share

Got this working now, many thank for your input!

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

9 People are following this question.

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

Related Questions

Yield Wait for Seconds (A little help here) 2 Answers

Need to call yield TWICE ??? (ANSWERED) 3 Answers

C# Wait for Coroutine 3 Answers

How to set timer for WWW helper? 1 Answer

Execution manner of co routine 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