Logic problem looping & timing
I'm having trouble calling a function at the correct time while looping. Either it calls it too fast or too slow. I thought I figured it out yesterday, but I didn't... Here is a diagram to show what I'm trying to do, I know I have some logic issue going on.
In Update() I call a function called blinkAtRandom(); This function has a timer that goes off X amount of time. When this timer goes off, it calls BlinkOnce();.
BlinkOnce() will change the texture for the eye animation, but only 1 texture per Y amount of time, so I want to loop through this eyelidTextures.Length amount of loops
The problem now, is looping ignores the timers so my results are either too "fast" (blink never can become false) or too "slow" (only changes 1 texture through an entire loop, and blink is always true).
Here is a sample of my code. I also want to point out if you stick BlinkOnce() by itself in update, it changes at the correct time and looks like Ideal Timing, so it works, it just can't be called from another function or I get the timing issues.
int BlinkOnce(float resetTime)
{
if (blink)
{
myTimer.x -= Time.deltaTime;
//timer finished
if (myTimer.x <= 0)
{
//StartCoroutine("OneBlink");
OneBlinkF();
myTimer.x = resetTime;
eyeFrame += 1;
}
//go through all of blink frames
if (eyeFrame > eyelidTextures.Length)
{
//stop blinking
blink = false;
eyeFrame = 0;
}
}
return 1;
}
Here is my other function
void blinkAtRandom()
{
myTimer2 -= Time.deltaTime;
if (myTimer2 <= 0)
{
//blink = true;
for (int i = 0; i < eyelidTextures.Length; i++)
{
BlinkOnce(myTimer.y);
}
//reset timer
myTimer2 = Random.Range(eyeBlinkRange.x, eyeBlinkRange.y);
}
}
Both samples of code have been altered a great deal so they only show 1 of many test cases I've tried. This really should be easy, so I don't know how I ended up making this so complicated!
Answer by _Gkxd · Oct 01, 2015 at 07:54 PM
The piece of code below will print "A" once every half second. You might find it useful.
public void Start() {
StartCoroutine(DoSomethingEveryHalfSecond());
}
private IEnumerator DoSomethingEveryHalfSecond() {
while (true) {
Debug.Log("A");
yield return new WaitForSeconds(0.5f);
}
}
I figured out the problem was, I needed to have 1 coroutine with a bunch of yields in it as opposed to 3 with each their own yield for x seconds. That was what was giving me the ti$$anonymous$$g trouble. Anyway, got my code working, thanks!
IEnumerator blinkAtRandomI()
{
while (true)
{
for (int i= 0; i < eyelidTextures.Length; i++)
{
//StartCoroutine(OneBlinkI(myTimer.y));
StartCoroutine("OneBlink");
yield return new WaitForSeconds(timeBetweenFrames);
Debug.Log(i);
}
Debug.Log("Done, time to restart~");
var t = Random.Range(timeUntilNextBlink.x, timeUntilNextBlink.y);
Debug.Log(t);
yield return new WaitForSeconds(t);
}
}
Answer by rageingnonsense · Oct 01, 2015 at 08:26 PM
Are you sure this is not because you are doing this in Update()? Update is not guarenteed to be called at fixed intervals, and could be contributing to the problem.
Try moving the code to FixedUpdate(), and see if it improves.
Also, _Gkxd's method would work.
Well, I have made them all into Coroutines but I'm still having trouble. FixedUpdate and LateUpdate won't fix a logic issue... :/
It flashes like mad now, but it's starting to sorta work, kinda, it flashes at the right time for one of my coroutines so I think I'm getting close, now if only I could get them to match up correctly and slowdown a bit... (Okay, I realized the ti$$anonymous$$g was better because I used the function version not the coroutine version, so I think I'll have to revert back to functions...) Update vs LateUpdate vs FixedUpdate really no noticeable difference in my scene btw. (Also since I'm using time.deltaTime it should be comparable to FixedUpdate...)
Hmmm... After more testing ~ coroutines are super fast so if there were some way to slow them down by like 90% I would be maybe okay... $$anonymous$$y blinkrange is 5-7 seconds, my resetTime is set to 15 seconds, timer2 set to 30sec... it just seems to be flickering.... I don't know coroutines seem to be a lot harder to control then regular functions... :/
And yes, yes timescale is set to 1.
void FixedUpdate () {
//blinkAtRandom();
//BlinkOnce(myTimer.y);
StartCoroutine("blinkAtRandomI");
}
...
IEnumerator blinkAtRandomI()
{
//blink = true;
for (int i = 0; i < eyelidTextures.Length; i++)
{
//BlinkOnce(myTimer.y);
StartCoroutine(OneBlinkI(myTimer.y));
}
blink = true;
yield return new WaitForSeconds(Random.Range(eyeBlinkRange.x, eyeBlinkRange.y));
//myTimer2 = Random.Range(eyeBlinkRange.x, eyeBlinkRange.y);
}
...
IEnumerator OneBlinkI(float resetTime)
{
while (blink)
{
StartCoroutine("OneBlink");
eyeFrame += 1;
//go through all of blink frames
if (eyeFrame > eyelidTextures.Length)
{
//stop blinking
blink = false;
eyeFrame = 0;
}
yield return new WaitForSeconds(resetTime);
}
}
....
The problem with your code right now is that you are starting a coroutine every time FixedUpdate (or Update) is called.
This means you're starting a coroutine every frame (in the case of Update), or every physics time step (in the case of FixedUpdate), which defeats the purpose of waiting for a certain amount of time. (I.e. the first coroutine will wait for some time, but during that time, another coroutine will run and make your image flash.)
I have provided a solution that avoids this problem by starting the coroutine inside Start, so that only one coroutine is running.
Well, I've moved it to start, it will probably work after I fiddle with it so more. Coroutines keep repeating, until I tell them to stop correct? It should work at some point so I'll go with your answer and give you the credit.
Your answer
Follow this Question
Related Questions
Unity update does not be called when lock screen 0 Answers
How do I convert this into C# and where should this be added? 1 Answer
Boolean set to true, false in Update() function because of Start() 1 Answer
onEnable & onDisable & onCollision never get called i have no idea y ?! 1 Answer
How to rotate camera 90 degrees but still keep control orientation in 2.5d? 0 Answers