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
0
Question by artwen · Nov 18, 2017 at 09:12 AM · coroutinetimerwaitforseconds

Making a timer using WaitForSecondsRealtime without keyword 'new'?

Hi guys, I did a simple timer using WaitForSecondsRealtime within a Coroutine and it worked:

 using UnityEngine;
 using UnityEngine.UI;
 using System.Collections;
 public class Timer : MonoBehaviour
 {
     Text txt;
     int startTime = 10;
 
     void Awake()
     {
         txt = GetComponent<Text>();
     }
     void Start()
     {
         StartCoroutine(CoroutineTimer());
     }
     IEnumerator CoroutineTimer()
     {
         while (startTime >= 0)
         {
             txt.text = startTime.ToString();
             startTime -= 1;
             yield return new WaitForSecondsRealtime(1);
         }
     }
 }

However, if I want to reduce garbage by removing the keywords 'new', and change the IEnumerator to below, it magically doesn't work anymore:

 IEnumerator CoroutineTimer()
 {
     WaitForSecondsRealtime countTime = new WaitForSecondsRealtime(1);
     while (startTime >= 0)
     {
         txt.text = startTime.ToString();
         startTime -= 1;
         yield return countTime;
     }
 }
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
2
Best Answer

Answer by FlaSh-G · Nov 18, 2017 at 11:53 PM

It's not very magical. A WaitForSeconds object is a simple timer. The time measured does not reset without any specific reason to - beacause that would be pretty magical. As a result, the object will never wait again.

You can, however, use a custom WaitForSeconds object that has a reset function. I've written one for you:

 using UnityEngine;
 
 public class WaitTimer : CustomYieldInstruction
 {
     private float timeLeft;
     private float lastTime;
 
     public override bool keepWaiting
     {
         get
         {
             timeLeft -= Time.deltaTime;
             return timeLeft > 0;
         }
     }
 
     public WaitTimer(float time)
     {
         Reset(time);
     }
 
     public void Reset(float time = 0)
     {
         if(time == 0)
         {
             timeLeft = lastTime;
         }
         else
         {
             lastTime = timeLeft = time;
         }
     }
 }

You need to reset the timer before using it again:

 var timer = new WaitTimer(3);
 yield return timer;
 Debug.Log("3");

 timer.Reset();
 yield return timer;
 Debug.Log("6");
 
 timer.Reset(4);
 yield return timer;
 Debug.Log("10");

If you like inplace methods, you could add a function in addition to Reset that returns the timer:

 public WaitTimer Again(float time = 0)
 {
     Reset(time);
     return this;
 }

and then use it like this:

 var timer = new WaitTimer(3);
 yield return timer;
 Debug.Log("3");
 yield return timer.Again();
 Debug.Log("6");
Comment
Add comment · Show 3 · 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 Bunny83 · Nov 19, 2017 at 12:50 AM 2
Share

Actually the question title is misleading. WaitForSeconds would work the way he uses it as it has "native" support by the coroutine scheduler. So a WaitForSeconds object contains no logic at all and just a single float value which is the desired wait time. So WaitForSeconds can be "reused" / cached without problem. Same is true for WaitForEndOfFrame and WaitForFixedUpdate.


However "WaitForSecondsRealtime" (which is not what has been written in the question title) is actually a CustomYieldInstruction and is defined like this:

 public class WaitForSecondsRealtime : CustomYieldInstruction
 {
     private float waitTime;
     public override bool keepWaiting
     {
         get
         {
             return Time.realtimeSinceStartup < this.waitTime;
         }
     }
     public WaitForSecondsRealtime(float time)
     {
         this.waitTime = Time.realtimeSinceStartup + time;
     }
 }

So as you can see once created the internal wait time of course won't be updated when you "reuse" it

avatar image artwen Bunny83 · Nov 21, 2017 at 07:59 AM 0
Share

You're right, I changed the title.

avatar image Bunny83 · Nov 19, 2017 at 01:06 AM 2
Share

Just for completeness, the WaitForSeconds object looks like this:

 [RequiredByNativeCode]
 [StructLayout(Layout$$anonymous$$ind.Sequential)]
 public sealed class WaitForSeconds : YieldInstruction
 {
     internal float m_Seconds;
     public WaitForSeconds(float seconds)
     {
         this.m_Seconds = seconds;
     }
 }

The CustomYieldInstruction is pretty new. Along with that they shipped a few built-in implementations where "WaitForSecondsRealtime" is one of them. The other two are WaitWhile and WaitUntil which takes a predicate as parameter.


The CustomYieldInstruction class itself is just an IEnumerator implementation and looks like this:

 public abstract class CustomYieldInstruction : IEnumerator
 {
     public abstract bool keepWaiting { get; }
     public object Current { get { return null; } }
     public bool $$anonymous$$oveNext()
     {
         return this.keepWaiting;
     }
     public void Reset()
     {
     }
 }

Since this change they actually allow you to just yield an IEnumerator inside a coroutine and it will automatically start a new coroutine and yield on that coroutine ins$$anonymous$$d.


So when doing

 yield return new WaitForSecondsRealtime(5);

you actually do

 yield return StartCoroutine(new WaitForSecondsRealtime(5));

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

80 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 avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

SpeedBoost won't reset : Problem with either WaitForSeconds or Coroutine (Solved) 2 Answers

How to make WaitForSeconds work as a repeating/looping timer? 1 Answer

How to get Coroutine's remaining time in WaitForSeconds? 2 Answers

C# simple delay execution without coroutine? 2 Answers

How do I let the script wait a predetermined time? 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