Skip to content

03 Stage

In this chapter, we will add PreviewStage and draw the 10 temporary panels.

Stage Archetype

First, create guide/preview/stage.py and set up PreviewStage, a subclass of PreviewArchetype, as follows:

python
from sonolus.script.archetype import PreviewArchetype

from guide.lib import archetype_names


class PreviewStage(PreviewArchetype):
    name = archetype_names.STAGE

Using the same archetype name as play mode lets PreviewStage handle the Stage entity already present in the level.

Then register it in the archetypes list in guide/preview/mode.py:

python
from guide.preview.stage import PreviewStage

preview_mode = PreviewMode(
    archetypes=[
        PreviewInitialization,
        PreviewStage,
    ],
    skin=Skin,
)

Declaring

Even though the stage in play mode has only a judgment line, it is best to draw lanes and borders in preview so players can visualize each panel. Map fields in the shared Skin class to stage sprites from the StandardSprite class. In guide/lib/skin.py, add these fields to the existing Skin class. Keep all fields added in the Play and Watch sections. These fields reuse standard resources supplied by the selected skin, so no new image assets are needed:

python
from sonolus.script.sprite import StandardSprite, skin


@skin
class Skin:
    # ...

    stage_middle: StandardSprite.STAGE_MIDDLE
    stage_left_border: StandardSprite.STAGE_LEFT_BORDER
    stage_right_border: StandardSprite.STAGE_RIGHT_BORDER

Drawing

Preview calls each entity's render callback. In guide/preview/stage.py, add render and keep the panel loop in a separate render_panels method. Each loop iteration offsets one panel by PANEL_WIDTH. The lane occupies the middle 3 units and the borders sit on its left and right edges:

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

from guide.lib.skin import Skin
from guide.preview.chart import PANEL_COUNT, PANEL_HEIGHT, PANEL_WIDTH


class PreviewStage(PreviewArchetype):
    def render(self):
        self.render_panels()

    def render_panels(self):
        for i in range(PANEL_COUNT):
            x = i * PANEL_WIDTH

            middle = Rect(l=-1.5, r=1.5, b=0, t=PANEL_HEIGHT).translate(Vec2(x, 0))
            left_border = Rect(l=-1.75, r=-1.5, b=0, t=PANEL_HEIGHT).translate(Vec2(x, 0))
            right_border = Rect(l=1.5, r=1.75, b=0, t=PANEL_HEIGHT).translate(Vec2(x, 0))

            Skin.stage_middle.draw(middle, z=0)
            Skin.stage_left_border.draw(left_border, z=0)
            Skin.stage_right_border.draw(right_border, z=0)

Checkpoint

Refresh Preview in the Sonolus app. You should be able to scroll horizontally through 10 panels. Each panel should contain the 3-unit-wide lane between two borders.