Doing something on an interval, every X amount of time

I seem to be able to see them, but not change them in functions. Looking at the fireflies example, I’m trying to do something similar. It works, but what I’m doing doesn’t.

I’m not seeing what boneheaded mistake I’m making.

I added “flake_o” to try and sweep a white pixel through the string and nothing I’m trying seems to work. I get a white pixel at location 40 that does not move.

  flake_rate = .1;
    
  export var flake_count = 10;
  export var flakes = array(flake_count) // hold indices of active flakes
  
  export var flake_on = array(pixelCount)
  
  export var flake_o = 40;
  flake_value = array(pixelCount)
  flake_dir = array(pixelCount)
  
  for (i = 0; i < pixelCount-1; i++) {
    flake_on [i] = 0;
    flake_value[i] = 0;
    flake_dir[i] = 0;
  }
  
  export var flake_index
  
    for (i = 0; i < flake_count-1; i++) {
      flakes[i] = floor(random(pixelCount))
      flake_on [flakes[i]] = 1;
    }
///////////////////////////////////////////////////////////////////////////////  
  
export function beforeRender(delta) {
  
  t1 = time(.15)
  
  if(t1 == 1){
    
    flake_on[flakes[flake_index]] = 0;
    flake_value[flakes[flake_index]] = 0;
    
    flakes[flake_index] = random(pixelCount) // pick a new pixel snowflake
    
    flake_on[flakes[flake_index]] = 1;
    
    flake_index = clamp(flake_index ++,0,flake_count)
    
    flake_o = flake_o + 1;
  //  flake_o = clamp(flake_o,0,pixelCount)
    
  }

}

/////////////////////////////////////////////////////////////////////////////

export function render(index) {
  
  hsv(1,1,1)
  
  if((index%2)){
    hsv(.33,1,1)
  }
  
  /*
  if (flake_on[index]==1){
    hsv(0,0,abs(2*t1-1))
  }
  */
  
  if(flake_o == index){
    hsv(0,0,1)
    
  }
}

Hi Oz! Here’s your issue:

t1 is a sawtooth from 0 to 1, but you’re not guaranteed (and in fact it’s nearly impossible) to ever catch it in a beforeRender() exactly at == 1. So here are a few alternatives for two goals:

  1. Do something every X milliseconds – I’ll start with “too clever” and end with “canonical”
  2. Sweep a pixel across the strip

Clever bad idea 1: change it to if (t1 > .99){ and tune the .99. Downside: 1% of the time, it will advance a bunch - maybe too much. beforeRender() might be called when t1 is .991, then .993, then .995, .997, .999, then .001… you get it. flake_o is incremented 5 times in a burst, for 1% of all beforeRenders. Worse, it’ll be inconsistent when the overall program timing changes just from adding new code (and the time between calls to beforeRender() increases).

Clever bad idea 2: Use state to store the last value of t1 from the last beforeRender(). Do something once if we detect that t1 has looped.

var lastT1
var period = 2 * 1000 // Every 2000 milliseconds...
export function beforeRender(delta) {
  t1 = time(period / 65.536)
  if (t1 < lastT1) { doOnceEveryPeriod() }
  lastT1 = t1
}

The gotcha: you’ll encounter a situation where system management code had a large, rare delay, so delta is large, and t1 looped but past a full sawtooth cycle and its lastT1 value. This results in stutters. E.g., imagine t1 values of .2, .4, .6, (massive delay, t1 loops through 0) and the next t1 is .9 <-- We shoulda triggered our doOnceEveryPeriod(), but we’ll not be able to detect it.

The recommended solution: Accumulate delta

var period = 2 * 1000 // Every 2000 milliseconds...
var accumulatedDelta = 0
export function beforeRender(delta) {
  accumulatedDelta += delta
  if (accumulatedDelta >= period) {
    // Choose between: 
    accumulatedDelta = 0 // or
    accumulatedDelta -= period // More accurate, but better be able to keep up!
    doOnceEveryPeriod()
  }
}

 

Is there an easier way to sweep one pixel?

It might not work for you, but look into:

export function render(index) {
  if (floor(t1 * pixelCount) == index) hsv(0, 0, 1)
  else hsv(0, 0, 0)
}

You can add delays and buffer by modifying it with if (floor((t1 - offset) * scale * pixelCount) == index) {

Hope this has been useful!

Sidenote… I usually find myself using a pattern like for (i = 0; i < flake_count; i++) - might want to check if you really need those -1s in some places.

Consider renaming the title of your post so it best helps the next person searching. This title implies a variable scope issue, but the real issue is about using time() or doing something on an interval.

3 Likes

Thanks. I knew I was blind to something.

I knew I’d read your list of methods, thanks for linking to it, great write-up

1 Like