Timer

run code on a delay or at a repeating interval.

▶ Run in browser

Tags: 2d timer signals

A Timer is a node that counts down its duration in seconds and then emits its timeout signal. Add it as a child and connect a handler, like any other signal:

timer = self.add_child(Timer(duration=0.8, one_shot=False, autostart=True))
timer.timeout.connect(self.spawn)
  • one_shot=True (the default) fires once and stops: a delayed action.

  • one_shot=False repeats until stop(): an interval. Leftover time carries into the next cycle, so the interval does not drift at a low frame rate.

  • autostart=True starts counting at once; otherwise call start().

  • time_left is the seconds remaining, handy for driving an animation.

Here a repeating timer on the root spawns a pulse every 0.8 seconds and counts the ticks. Each pulse owns a one-shot timer: it reads time_left to grow and fade its disc, and connects timeout to destroy, so it removes itself after one second with no bookkeeping in the root.

Source

 1# /// simvx
 2# tags = ["2d", "timer", "signals"]
 3# screenshot_frame = 90
 4# web = { width = 800, height = 600, responsive = true }
 5# ///
 6"""Timer: run code on a delay or at a repeating interval.
 7
 8A `Timer` is a node that counts down its `duration` in seconds and then emits its
 9`timeout` signal. Add it as a child and connect a handler, like any other signal:
10
11    timer = self.add_child(Timer(duration=0.8, one_shot=False, autostart=True))
12    timer.timeout.connect(self.spawn)
13
14- `one_shot=True` (the default) fires once and stops: a delayed action.
15- `one_shot=False` repeats until `stop()`: an interval. Leftover time carries into
16  the next cycle, so the interval does not drift at a low frame rate.
17- `autostart=True` starts counting at once; otherwise call `start()`.
18- `time_left` is the seconds remaining, handy for driving an animation.
19
20Here a repeating timer on the root spawns a pulse every 0.8 seconds and counts the
21ticks. Each pulse owns a one-shot timer: it reads `time_left` to grow and fade its
22disc, and connects `timeout` to `destroy`, so it removes itself after one second
23with no bookkeeping in the root.
24"""
25
26import random
27
28from simvx.core import Anchor, CanvasLayer, Label, Node2D, Timer, VBoxContainer
29from simvx.graphics import App
30
31
32class Pulse(Node2D):
33    """An expanding, fading disc that removes itself when its timer runs out."""
34
35    dynamic = True  # on_draw animates every frame
36
37    def on_ready(self):
38        self.life = self.add_child(Timer(duration=1.0, autostart=True))
39        self.life.timeout.connect(self.destroy)
40
41    def on_draw(self, renderer):
42        f = min(1.0, 1.0 - self.life.time_left / self.life.duration)
43        renderer.circle((0, 0), 12 + f * 64, fill=(0.4, 0.8, 1.0, 1.0 - f))
44
45
46class TimerDemo(Node2D):
47    def on_ready(self):
48        self.ticks = 0
49        hud = self.add_child(CanvasLayer()).add_child(VBoxContainer(anchor=Anchor.TOP_LEFT, inset=16))
50        hud.add_child(Label("Timer: repeating + one-shot", font_size=28))
51        self.counter = hud.add_child(Label("ticks: 0"))
52        spawner = self.add_child(Timer(duration=0.8, one_shot=False, autostart=True))
53        spawner.timeout.connect(self.spawn)
54
55    def spawn(self):
56        self.ticks += 1
57        self.counter.text = f"ticks: {self.ticks}"
58        w, h = self.viewport_size
59        self.add_child(Pulse(position=(random.uniform(0.15, 0.85) * w, random.uniform(0.25, 0.85) * h)))
60
61
62if __name__ == "__main__":
63    App(title="Timer", width=800, height=600).run(TimerDemo())