Skip to content

09 Note Spawning ​

In this chapter, we will implement the spawning logic for Note.

Target Time ​

We first need to calculate a note's target time. Sonolus.py provides beat_to_time to convert a beat directly to time using the timing information provided by Sonolus.

Calculated Entity Data ​

In chapter 07, the level supplied imported fields in Entity Data for each Note. An archetype can also calculate Entity Data during preprocess instead of loading it from the level. A field declared with entity_data can be written during preprocess and is read-only afterward. Other entities can also read it.

Target time does not change after preprocessing, so store it in Entity Data:

python
from sonolus.script.archetype import PlayArchetype, StandardImport, entity_data
from sonolus.script.timing import beat_to_time


class Note(PlayArchetype):
    beat: StandardImport.BEAT

    target_time: float = entity_data()

    def preprocess(self):
        self.target_time = beat_to_time(self.beat)

Spawn Time ​

Set each Note's spawn time to 1 second before its target time. This gives the player time to see it fall from above.

Spawn time also does not change for a note entity, so calculate it during preprocess and store it in Entity Data:

python
class Note(PlayArchetype):
    # ...

    spawn_time: float = entity_data()

    def preprocess(self):
        # ...

        self.spawn_time = self.target_time - 1

Spawning Logic ​

Replace the temporary spawn_order callback from chapter 07 so Notes are spawned in order of their spawn time, after the setup entities.

Initialization and Stage use the negative spawn orders -10 and -9. In this guide's chart, every Note spawns after those setup entities and can use its spawn time directly:

python
class Note(PlayArchetype):
    # ...

    def spawn_order(self) -> float:
        return self.spawn_time

spawn_order controls the order in which Sonolus processes entities for spawning. It does not decide whether an entity is ready to spawn. Add should_spawn to make that decision for each Note:

python
from sonolus.script.runtime import time


class Note(PlayArchetype):
    # ...

    def should_spawn(self) -> bool:
        return time() >= self.spawn_time