Skip to content

06 Stage

In this chapter, we will implement the drawing logic for Stage.

Skin Sprites

By default, an engine does not have access to every sprite in the skin selected by the player. To use a sprite, the engine must declare it by name.

A skin sprite name is a string. Sonolus defines common names through StandardSprite. Compatible skins provide these standard sprites, allowing them to work across multiple engines. Engines can also use standard sprites as fallbacks when custom sprites are unavailable.

Declaring

Our stage is simple: it only contains the judgment line. Since we do not need a custom sprite, replace the contents of guide/lib/skin.py with this declaration:

python
from sonolus.script.sprite import StandardSprite, skin


@skin
class Skin:
    judge_line: StandardSprite.JUDGMENT_LINE

The Skin declaration is passed to PlayMode, which makes its declared sprites available to play callbacks.

Drawing

We will give the judgment line a thickness equal to one half of the note radius, extending one quarter of the radius on each side. Because the engine coordinate system places the judgment line at y = 1, the layout calculation is simple.

In guide/play/stage.py, delete the temporary debug_log and time imports. Then add these imports below the existing PlayArchetype import:

python
from sonolus.script.quad import Rect

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

Replace the temporary update_parallel callback with this drawing code:

python
class Stage(PlayArchetype):
    # ...

    def update_parallel(self):
        layout = Rect(
            l=Config.judge_line_l,
            r=Config.judge_line_r,
            t=1 - Config.note_radius / 4,
            b=1 + Config.note_radius / 4,
        )

        Skin.judge_line.draw(layout, z=0, a=1)

Sprite.draw accepts the rectangle as its layout. The z argument controls draw order, while a controls alpha.

Responding to Touches

Let's improve the judgment line by making it respond to touches(). The touches() function returns the touches in the current frame. Add this import after the Rect import:

python
from sonolus.script.runtime import touches

Then replace the Skin.judge_line.draw call in update_parallel:

python
class Stage(PlayArchetype):
    # ...

    def update_parallel(self):
        # ...

        Skin.judge_line.draw(layout, z=0, a=1 if touches() else 0.5)

Reopen the development level. The judgment line should be half-transparent with no touches and fully opaque while the screen is being touched.