05 Note Lifetime
In this chapter, we will create WatchNote and give each note a lifetime on the scaled watch timeline.
Note Archetype
Create guide/watch/note.py with this chapter's complete note implementation:
python
from sonolus.script.archetype import StandardImport, WatchArchetype, entity_data
from sonolus.script.interval import Interval
from sonolus.script.timing import beat_to_bpm, beat_to_time, time_to_scaled_time
from guide.lib import archetype_names
class WatchNote(WatchArchetype):
name = archetype_names.NOTE
beat: StandardImport.BEAT
target_time: float = entity_data()
visual_time: Interval = entity_data()
def preprocess(self):
self.target_time = beat_to_time(self.beat)
self.visual_time.end = time_to_scaled_time(self.target_time)
self.visual_time.start = self.visual_time.end - 120 / beat_to_bpm(self.beat)
def spawn_time(self) -> float:
return self.visual_time.start
def despawn_time(self) -> float:
return self.visual_time.endSonolus matches archetypes to level entities by name. WatchNote uses the same name as the play-mode Note archetype, so it handles the same entities.
Registration and Life
Register the new archetype in guide/watch/mode.py. The watch import block should now read:
python
from guide.watch.initialization import WatchInitialization
from guide.watch.note import WatchNote
from guide.watch.stage import WatchStage
from guide.watch.update_spawn import update_spawnThen replace only the archetypes argument with:
python
archetypes=[WatchInitialization, WatchStage, WatchNote],Now edit guide/watch/initialization.py. Import init_life and WatchNote, then call init_life(WatchNote) between score and UI setup. The completed file should contain:
python
from sonolus.script.archetype import WatchArchetype
from guide.lib import archetype_names
from guide.lib.buckets import init_buckets
from guide.lib.layout import init_layout
from guide.lib.note import init_life, init_score
from guide.lib.options import Options
from guide.lib.ui import init_ui
from guide.watch.note import WatchNote
class WatchInitialization(WatchArchetype):
name = archetype_names.INITIALIZATION
def preprocess(self):
init_buckets()
init_score()
init_life(WatchNote)
init_ui()
init_layout(Options.note_size)This reuses the life configuration from Play chapter 17.
Target and Visual Times
The entity_data declarations preserve the values calculated during preprocess for later callbacks. target_time is the note's level time. time_to_scaled_time converts it to the scaled timeline selected in chapter 02, and 120 / beat_to_bpm(self.beat) gives the note a visual duration equal to two beats at the note's BPM. This reuses the fall-time calculation from Play chapter 21.
Lifetime
The note is active from visual_time.start until visual_time.end. At this checkpoint, the note has a lifetime but is not visible and produces no feedback. The next four chapters add drawing, result data, sound, and particles. Chapter 10 changes the despawn time during replay to use the recorded hit time.