thanks @BoldBigflank - that's definitely a viable solution to animating the stars... but it doesn't help me understand what's happening with timers.
I've written some test code; first I tried creating 10 timers within a while loop:
on timerLoop do
if it_loop>0 then
log "timerLoop already running, please wait"
else
// it_loop=1
itL_local=0
while itL_local <10 do
itL_local++
it_loop++
log "kicking off timerLoop @ {itL_local}"
wait it_loop then
log "waited {it_loop} seconds"
it_loop--
end
end
// it_loop=0
end
end
Ignore the fact that my log messages can't work as intended due to all variables always being global... nonetheless you might expect 10 unique timers to run, each for a different duration, when this code executes. That doesn't happen though. Instead all 10 "kick off timerLoop..." log messages are emitted, then ~10 seconds elapses before all 10 "waited {it_loop} seconds" log messages are emitted, all at about the same time.
From this I assumed there might be only 1 timer and that multiple callbacks might be registered to that timer - so i end up with a single timer being reconfigured 10 times, eventually running for 10 seconds... but 10 unique callbacks executed when the timer finally expires.
To test this I created another function:
on timerDiscrete do
if it_discrete > 0 then
log "timerDiscrete already running, pleae wait"
else
log "kicking off timerDiscrete"
it_discrete=10
disc_0=1
disc_1=3
disc_2=5
disc_3=7
disc_4=9
disc_5=2
disc_6=4
disc_7=6
disc_8=8
disc_9=10
wait disc_0 then
it_discrete--
log "0: waited {disc_0}"
end
wait disc_1 then
it_discrete--
log "1: waited {disc_1}"
end
wait disc_2 then
it_discrete--
log "2: waited {disc_2}"
end
wait disc_3 then
it_discrete--
log "3: waited {disc_3}"
end
wait disc_4 then
it_discrete--
log "4: waited {disc_4}"
end
wait disc_5 then
it_discrete--
log "5: waited {disc_5}"
end
wait disc_6 then
it_discrete--
log "6: waited {disc_6}"
end
wait disc_7 then
it_discrete--
log "7: waited {disc_7}"
end
wait disc_8 then
it_discrete--
log "8: waited {disc_8}"
end
wait disc_9 then
it_discrete--
log "9: waited {disc_9}"
end
log "submitted 10 timers within timerDiscrete"
end
end
This script creates 10 unique timers of 10 different durations. When I run it I see "kicking off timerDiscrete" followed immediately by "submitted 10 timers...". Then, once per second thereafter, i see each of the 10 timers expire and emit their unique log messages. Here I can confirm that we CAN run at least 10 unique timers! I assume, then, that this is intentional - that Pulp Script was designed to allow for some plurality of timers.
That leaves me wondering why it fails in the timerLoop function? I wondered if perhaps the code scope with the while loop caused an issue in timer instantiation within the runtime, so I created another function:
on timerInline do
if it_inline>0 then
log "timerInline already running, please wait"
else
log "kicking off timerInline"
it_inline=10
it_local=1
wait it_local then // 1
it_inline-- // 9
log "waited 1 seconds"
end
it_local++
wait it_local then // 2
it_inline-- // 8
log "waited 2 seconds"
end
it_local++
wait it_local then // 3
it_inline-- // 7
log "waited 3 seconds"
end
it_local++
wait it_local then // 4
it_inline-- // 6
log "waited 4 seconds"
end
it_local++
wait it_local then // 5
it_inline-- // 5
log "waited 5 seconds"
end
it_local++
wait it_local then // 6
it_inline-- // 4
log "waited 6 seconds"
end
it_local++
wait it_local then // 7
it_inline-- // 3
log "waited 7 seconds"
end
it_local++
wait it_local then // 8
it_inline-- // 2
log "waited 8 seconds"
end
it_local++
wait it_local then // 9
it_inline-- // 1
log "waited 9 seconds"
end
it_local++
wait it_local then // 10
it_loop-- // 0
log "waited 10 seconds"
end
it_local++
log "submitted 10 timers with timerInline"
end
end
This function behaves effectively the same as timerLoop - I end up with just a single 10 second timer and 10 unique callbacks which execute when that single timer expires... so the issue isn't related to the while loop itself.
I next wondered if the issue might be related to how the runtime triggers timers - perhaps timer creation is queued up on each iteration of the super loop with a REFERENCE to the duration value, not a copy of it. therefore on a single iteration of the loop if we call for N timers we might get N timers to start at the end of that loop iteration... but their duration wouldn't be evaluated until that moment between frames, after one loop iteration and before the next one, therefore they would all have the same duration.
Ignore the naming changes below, I was starting to think of the timer as a watch dog timer (wdt):
on load do
num_wdt=0
wdt_dur=1
end
on feedTheDog do
log "fed the dog"
wdt_dur+=3
end
on watchDog do
wdt_dur+=2
num_wdt++
log "setting watch dog [{num_wdt}] @ {wdt_dur}"
wait wdt_dur then
log "the dog is hungry! [{num_wdt}]"
num_wdt--
end
end
on confirm do
// call "starEvent"
// call "timerLoop"
// call "timerDiscrete"
call "feedTheDog"
end
on cancel do
// call "timerInline"
call "watchDog"
call "watchDog"
end
Ok so this test is a little more complicated - i'm testing a couple things.
- i attached these watchDog and feedTheDog to my cancel and confirm events, respectively. I did this in the past too, as you can see in the commented-out code
- on cancel: i call "watchDog" twice. this means a single button tap will try to create 2 timers. note that the timer duration changes each time i call "watchDog"
- on confirm: i try increasing the value of my wdt_dur variable, to see if i can "feed the dog" (cause a timer that is already running to extend its duration before timing out)
Observations and conclusion
- calling "watchDog" twice in a single super loop iteration (twice in a single function call) recreated the issues originally seen; this effectively behaves like a single timer with the duration given by the last call to "wait", but all the callbacks are registered and execute.
- calling "watchDog" multiple times, even while other watchDog timers are running, but on DIFFERENT iterations of the super loop... results in every timer executing exactly as the code suggests (they all run properly)
- the most recent hypothesis, that the timers are all created with duration values by reference to the variable in the code appears CORRECT.
- if you want to run multiple timers concurrently and with the same variable holding the timer duration, then you'll need to start each timer on a unique iteration of the super loop
Final test
It felt wrong to hijack the player's DRAW handler, so i forward the game's LOOP handler to a loop handler within player:
// game script
on loop do
tell event.player to
call "loop"
end
end
// player script
on loop do
if num_wdt>10 then
wdt_go = 0
end
if wdt_go==1 then
call "watchDog"
end
end
on confirm do
wdt_go = 1
end
on watchDog do
wdt_dur += 2
num_wdt++
log "setting watch dog [{num_wdt}] @ {wdt_dur}"
wait wdt_dur then
log "the dog is hungry! [{num_wdt}]"
num_wdt--
end
end
This code creates my 10 unique timers without issues! each one starts about 1/20th of a second after the prior timer, but that could be accounted for in the script if you really want to.
With the above we can create arbitrary numbers of timers
Linking this into something like the original star animation code might be ugly... you can't just kick off a timer from within each star ... but i'll leave that as an exercise for another day.
I wonder, though, whether this is a bug or a feature?
I might try to summarize this post before pulling in a moderator - it's a long one and i'm sure they are pretty busy already.
-bit