06 Printing Times
In this chapter, we will print whole-second time labels in the left margin of each panel.
Printing
Although preview already works and displays every note, it is easy for players to get lost while scrolling around.
This is why we left space on each side of a panel. We can use it to print helpful information such as the time and measure number. In later chapters, we will also use this space to print BPM and time scale changes.
Unlike sprite drawing, print_number expects its anchor and dimensions in screen coordinates. The print_at_time function transforms the chart position with the skin transform. It also clamps the anchor away from the top and bottom edges so the text remains visible.
In guide/preview/chart.py, add a utility function using the print_number API:
python
from typing import Literal
from sonolus.script.interval import Interval
from sonolus.script.printing import PrintColor, PrintFormat, print_number
from sonolus.script.runtime import HorizontalAlign, screen, skin_transform
from sonolus.script.vec import Vec2
def print_at_time(
value: float,
time: float,
*,
fmt: PrintFormat,
decimal_places: int = -1,
color: PrintColor,
side: Literal["left", "right"],
):
print_number(
value=value,
fmt=fmt,
decimal_places=decimal_places,
anchor=_get_anchor(
pos_at_time(time) + Vec2(-1.5 if side == "left" else 1.5, 0)
),
pivot=Vec2(1 if side == "left" else 0, 0.5),
dimensions=Vec2(screen().h / 10, screen().h / 20),
color=color,
horizontal_align=HorizontalAlign.RIGHT
if side == "left"
else HorizontalAlign.LEFT,
background=False,
)
def _get_anchor(position: Vec2):
anchor = skin_transform().transform_vec(position)
anchor.y = Interval(screen().b, screen().t).shrink(screen().h / 40).clamp(anchor.y)
return anchorTimes
In guide/preview/stage.py, add print_times to PreviewStage and call it from render after render_panels. The loop starts at 1 so a time label does not obstruct the BPM or time scale markers at the beginning of the level:
python
from math import floor
from sonolus.script.printing import PrintColor, PrintFormat
from guide.preview.chart import Chart, print_at_time
class PreviewStage(PreviewArchetype):
# ...
def render(self):
# ...
self.print_times()
def print_times(self):
for time in range(1, floor(Chart.duration) + 1):
print_at_time(
time,
time,
fmt=PrintFormat.TIME,
decimal_places=0,
color=PrintColor.NEUTRAL,
side="left",
)This guide prints time information on the left, beat information on the right, and regular labels in a neutral color.
Checkpoint
Refresh Preview. Neutral time labels should appear in the left margin at 1 second, 2 seconds, and each later whole second through the end of the sample level. There should be no time label at 0.