Skip to content

05 Note Display ​

In this chapter, we will implement the note drawing functions.

Existing Sprite ​

The shared Skin already declares the note sprite from play mode. This code is for reference. Do not edit guide/lib/skin.py:

python
@skin
class Skin:
    # ...
    note: StandardSprite.NOTE_HEAD_CYAN

Note Drawing Function ​

Create guide/tutorial/note.py with a draw_note function. It draws the note at a given height, scale, and alpha using Rect and Vec2:

python
from sonolus.script.quad import Rect
from sonolus.script.vec import Vec2

from guide.lib.layout import Config
from guide.lib.skin import Skin


def draw_note(y: float, scale: float = 1, alpha: float = 1):
    size = 2 * Config.note_radius * scale
    layout = Rect.from_center(Vec2(0, y), Vec2(size, -size))
    Skin.note.draw(layout, z=1, a=alpha)

The note uses layer 1, so it appears in front of the judgment line in layer 0. The negative height in Vec2(size, -size) accounts for the transformed vertical axis.

Timing ​

In guide/tutorial/note.py, add these durations after the imports:

python
INTRO_DURATION = 1
FALL_DURATION = 2
FROZEN_DURATION = 4
PAUSE_DURATION = 1

The next chapter will chain these durations into a timeline. Each drawing function receives the time elapsed within its part of the phase. PAUSE_DURATION creates a blank delay before the phase repeats.

Drawing ​

In guide/tutorial/note.py, add the imports from sonolus.script.interval, then add the three drawing functions after draw_note.

The intro draws an enlarged note near the center of the screen and fades it during the final quarter. The remap_clamped function keeps the fade within its specified range:

python
from sonolus.script.interval import remap, remap_clamped


def draw_intro(elapsed: float):
    alpha = remap_clamped(0.75 * INTRO_DURATION, INTRO_DURATION, 1, 0, elapsed)
    draw_note(0.5, scale=2, alpha=alpha)

The fall uses remap to map its elapsed time to the note's vertical position:

python
def draw_fall(elapsed: float):
    y = remap(0, FALL_DURATION, 0, 1, elapsed)
    draw_note(y)

The frozen part draws the note at the judgment line. We will add its instructions in a later chapter:

python
def draw_frozen(elapsed: float):
    draw_note(1)

Finally, add this placeholder after the drawing functions. Later chapters will replace its body with the hit effects:

python
def play_note_hit_effects():
    pass

The note is not visible yet because these drawing functions are not scheduled until the next chapter.