18 SFX
In this chapter, we will add sound effects (SFX) to Note and Stage.
Define the Effect Clips
Effect clips are the sounds an engine can play. Open guide/lib/effect.py and replace its placeholder Effects class with these standard clips:
python
from sonolus.script.effect import StandardEffect, effects
@effects
class Effects:
stage: StandardEffect.STAGE
perfect: StandardEffect.PERFECT
great: StandardEffect.GREAT
good: StandardEffect.GOODPlay Judgment Sounds
In Note.touch in guide/play/note.py, add this match after the existing result assignments. It plays the clip for the recorded judgment. The distance argument prevents the same clip from playing again for the specified number of seconds. A value of 0.02 avoids stacking the same sound during rapid hits. Keep the existing callback decorator unchanged.
python
from sonolus.script.bucket import Judgment
from guide.lib.effect import Effects
class Note(PlayArchetype):
# ...
def touch(self):
# ...
for touch in touches():
# ...
match self.result.judgment:
case Judgment.PERFECT:
Effects.perfect.play(0.02)
case Judgment.GREAT:
Effects.great.play(0.02)
case Judgment.GOOD:
Effects.good.play(0.02)
# ...
# ...Play Sounds for Unclaimed Taps
The judgment line already reacts to taps, so Stage should play a sound for taps that no Note used. Add this callback to Stage in guide/play/stage.py:
python
from sonolus.script.archetype import callback
from sonolus.script.runtime import touches
from guide.lib.effect import Effects
from guide.play.input_manager import touch_is_used
class Stage(PlayArchetype):
# ...
@callback(order=2)
def touch(self):
for touch in touches():
if not touch.started:
continue
if touch_is_used(touch):
continue
Effects.stage.play(0.02)
return
# ...Callback order makes the ownership check reliable: Input Manager clears used touches at order 0, Note claims its touches at order 1, and Stage inspects the remaining touches at order 2. The return limits Stage to one sound per frame.
Checkpoint
Run the level and tap a Note, then tap an empty part of the judgment line. The first tap should play only a judgment sound. The second should play the stage sound.