1
\$\begingroup\$

I'm trying to make an element (3D object or UI element) blink in such way:

  1. There is a timer which counts down 10.0f seconds to 0.0f.
  2. In 10.0f to 9.9f range the object should fade out from opacity 1 to 0.
  3. In 9.9f to 9.8f range the object should fade back in from 0 to 1.
  4. Then wait 300ms.
  5. Then repeat and finally fade out and disappear completely on last 1.0f to 0.0f.

I created a function in Unity:

void Update(){
    if ( myTimeVariable < 10.0f && myTimeVariable > 9.9f ) {
        gameObject.GetComponent<Renderer>().material.color.a = (10.0f - myTimeVariable);
    } else if() {
        // The logic continues and makes a long set of
        // else if statements to cover all times.
    }
}

(It's originally a coroutine that executes after each Update() but here it's shown otherwise for simplicity reasons.)

The problem I'm facing is that at 60 FPS I have these frames available:

0ms 16ms 33ms 50ms 66ms 83ms 100ms

And on 30 FPS I may have only these:

0ms 33ms 66ms 100ms

On 30 FPS opacity is changing this way: First I get fully opaque object on 0ms frame. Then on 33ms frame I get 0.67 opaque object. Then on 66ms frame I get 0.34 opaque object and frame 100ms doesn't belong to "fade out" if statement but fading in starts. Object starts to fade in from 0.34 to 1 over the next 100ms even if it never had 0 opacity state.

It seems that my method of making blinking object is flawed. It never reaches 0 opacity and it's very visible in the game that the last state was 0.34 opacity and not 0. Is there a way to make that blinking be certain to go to 0 opacity regardless of frame rate?

Edit: For "fade in" I only call Unity's CrossFadeAlpha() once. That's why it starts from 0.34 and goes to 1 but even if I changed that to the other method still my frames may be available at 80ms and then 120ms and opacity 0.2 -> 0.2 is the result (never desired 0).

\$\endgroup\$
4
  • \$\begingroup\$ are you sing Time.DeltaTime to measure your time ? You might want to consider a fps independent timer. \$\endgroup\$
    – Uri Popov
    Commented Apr 27, 2016 at 10:07
  • \$\begingroup\$ I'm using Time.time to prepare myTimeVariable. 10.0f is 10 seconds regardless of FPS. \$\endgroup\$
    – fyvaydmx
    Commented Apr 27, 2016 at 11:04
  • \$\begingroup\$ If you want variable to change from 0 to 10 in 10 seconds in Update function no matter framerate, then you need to add Time.deltaTime to it. If framerate is 1fps, Time.deltaTime will be equal to 1. Means in 10 frames you get 10. If your fps is 2, Time.deltaTime will be equal to 0.5, means in 10 frames you get 5, but in 10 seconds you get 10(20 frames). Etc. You didn't explain exactly how you are using myTimeVariable but I assume you just want myTimeVariable += Time.deltaTime \$\endgroup\$
    – Nick
    Commented Apr 17, 2020 at 14:44
  • \$\begingroup\$ Also if this fading sequence is so complex, you are using a game engine which just allows you to create Animation and animate any script variable, which would be much better solution. Animation also allows you to create event listenters and call custom functions when hitting certain keyframes. \$\endgroup\$
    – Nick
    Commented Apr 17, 2020 at 14:47

3 Answers 3

1
\$\begingroup\$

Update is called once a frame, this means that the time between calls depends directly on the frame-rate. This problem can be solved by defining the alpha, a, as a function of t, where 0 \leq t \leq 10. At t = 10, a = 1, and at t = 0, a = 0, so we can define our function as f(t) = 0.1 * t. Psuedo code could appear as follows.

// initialize t=0
Update:
  t += Time.deltaTime
  if ( inRange(t, 0, 10) )
    setAlpha(0.1 * t)
  else
    setAlpha(0)

In Unity, Time.deltaTime expresses how much time in seconds has elapsed since the last frame.

\$\endgroup\$
0
\$\begingroup\$

For stylish control:

Define this 50-length array A of numbers:

1,0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

These are alpha values for 1/2 second, which is the repeat sequence for the 9 s blinking part of your question (0.1 + 0.1 + 0.3 s). These 9 seconds hold 18 repetitions of 0.5 seconds each. You only specify the 0.5 seconds with this array. As you can see, the values begin with 1, 10 slots later (= 0.1 s later) you have 0, then back to 1, where it stays for 30 numbers (0.3 s). After this, it can repeat.

Whenever you visit your function, you have a time T handy (as you stated).

Change your T value to start from 0 and end at 10. Ie. you have values of T like:

0, 0.33, 0.66, ... 5.99, 6.32, ... [any]

Use the value of T to index into the array A of 50 elements, and pick your alpha there. Index using this statement (pseudo code):

IND = 1 + modulo(floor(100 * T), 50)

This will produce a number between 1 and 50, no matter what T is. If for example T=0, IND will be 1. If T=0.05, IND will be 6. If T=7.142857, IND will be 15. If T=9, IND will be 1. Etc. Remove the "1 +" if your language uses zero-origin.

Your functions would look like this (sorry, i don't know the expressions for modulo and floor, ie. round down, in your language):

A = (array of) 1,0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
B = (array of) 0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0 // For the last fade out (length 1 second)

and in the loop:

:If (T > 10)
    [exit this thingy, do housekeeping]
:else
    :If (T < 9)
        IND = 1 + modulo(floor(100 * T), 50) // modulo(dividend, divisor)
        alpha = A[IND]
    :Else
        IND = 1 + modulo(floor(10 * T), 10) // could simplify into alpha = 10 - T
        alpha = B[IND]
    :End
    [set alpha to your object]
:end

Of course, you can now make different sequences, change the lenght of them, make other effects, etc.

\$\endgroup\$
-1
\$\begingroup\$

You could try calling it inside FixedUpdate() function

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Can you elaborate? Why would you use FixedUpdate instead of Update in this case? How would that decision affect the code you would write (Time.deltaTime vs. Time.fixedDeltaTime, for example)? And now would you implement the part of the requirements the author of the question doesn't know how to implement themselves? \$\endgroup\$
    – Philipp
    Commented Apr 17, 2020 at 14:01
  • \$\begingroup\$ Note that just because the value goes to 0 inside FixedUpdate, doesn't mean the player will see that. Multiple FixedUpdates can run back-to-back in a single displayed frame, so we can still hit the same problem, where the displayed state skips-over the 0 and displays some partial brightness from the latest evaluation. I don't agree that this does not provide an answer to the question, but I think as it stands this answer is wrong and should be edited to correct the issue. \$\endgroup\$
    – DMGregory
    Commented Apr 17, 2020 at 16:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .