Skip to content

08 Beat Lines

In this chapter, we will draw a grid line at each whole beat and make measure boundaries more visible.

Lines

Lines help players determine a note's position more precisely.

As with the printing logic, add a utility function using the Rect layout type to guide/preview/chart.py. It converts the beat to a chart position and draws a line across the 3-unit-wide lane:

python
from sonolus.script.quad import Rect
from sonolus.script.sprite import Sprite
from sonolus.script.timing import beat_to_time
from sonolus.script.vec import Vec2


def draw_line(sprite: Sprite, beat: float, order: float, a: float = 1):
    position = pos_at_time(beat_to_time(beat))
    layout = Rect.from_center(position, Vec2(3, 0.01))
    sprite.draw(layout, z=(1, order), a=a)

Timing lines use layer 1, above the stage and below Notes. The second value orders lines that share a beat. Regular beat lines use order 0. The next two chapters give change markers higher orders.

Declaring

In guide/lib/skin.py, map a field in the shared Skin class to a standard grid sprite. Keep the existing fields. This reuses the grid resource from the selected skin:

python
@skin
class Skin:
    # ...

    beat_line: StandardSprite.GRID_NEUTRAL

Beat Lines

In guide/preview/stage.py, add render_beats and call it in render after render_panels and before the two printing methods. The higher alpha makes every fourth beat, including beat 0, a stronger measure line:

python
from guide.preview.chart import draw_line


class PreviewStage(PreviewArchetype):
    # ...

    def render(self):
        # ...

        self.render_beats()

        # ...

    def render_beats(self):
        for beat in range(floor(Chart.beats) + 1):
            draw_line(Skin.beat_line, beat, order=0, a=0.25 if beat % 4 == 0 else 0.125)

    # ...

Checkpoint

Refresh Preview. A line should cross the lane at each whole beat. Lines at beats 0, 4, 8, and later multiples of 4 should be darker than the lines between them.