Skip to content

16 Arcade Score ​

In this chapter, we will set up arcade score and primary metric UI.

Configure Judgment Multipliers ​

The level score stores scoring settings shared by every scored archetype. Create guide/lib/note.py and add an init_score helper. A Perfect receives the full base multiplier. Great and Good receive smaller multipliers:

python
from sonolus.script.runtime import level_score


def init_score():
    level_score().update(
        perfect_multiplier=1,
        great_multiplier=0.75,
        good_multiplier=0.5,
    )

Sonolus normalizes the maximum arcade score to 1,000,000. The values above are relative weights in that calculation, not points added to the score.

Add a Consecutive Great Bonus ​

A consecutive Great bonus counts consecutive judgments graded Great or better. Add these fields to the existing level_score().update call in init_score: every 10 such judgments adds 0.01 to the multiplier. The bonus uses at most 50 consecutive judgments, so it stops increasing at 0.05.

python
def init_score():
    level_score().update(
        # ...
        consecutive_great_multiplier=0.01,
        consecutive_great_step=10,
        consecutive_great_cap=50,
    )

Open guide/play/initialization.py and call init_score() once from Initialization.preprocess:

python
from guide.lib.note import init_score


class Initialization(PlayArchetype):
    def preprocess(self):
        # ...
        init_score()
        # ...

Show Arcade Score ​

The primary metric bar shows progress toward the maximum score, while the primary metric value shows the current raw score.

Add UiMetric to the existing sonolus.script.ui import in guide/lib/ui.py, then select arcade score explicitly while preserving the other UiConfig arguments:

python
from sonolus.script.ui import UiConfig, UiMetric


ui_config = UiConfig(
    primary_metric=UiMetric.ARCADE,
    # ...
)

In the same file, add both layouts to init_ui immediately after ui.combo_text.update(...). Place the metric value inside the metric bar:

python
from sonolus.script.runtime import HorizontalAlign, runtime_ui, safe_area, screen
from sonolus.script.vec import Vec2


def init_ui():
    ui = runtime_ui()

    # ...

    ui.primary_metric_bar.update(
        anchor=safe_area().tr - Vec2(0.05, 0.05),
        pivot=Vec2(1, 1),
        dimensions=Vec2(0.75, 0.15) * ui.primary_metric_config.scale,
        rotation=0,
        alpha=ui.primary_metric_config.alpha,
        horizontal_align=HorizontalAlign.LEFT,
        background=True,
    )
    ui.primary_metric_value.update(
        anchor=(
            safe_area().tr
            - Vec2(0.05, 0.05)
            - Vec2(0.035, 0.035) * ui.primary_metric_config.scale
        ),
        pivot=Vec2(1, 1),
        dimensions=Vec2(0, 0.08) * ui.primary_metric_config.scale,
        rotation=0,
        alpha=ui.primary_metric_config.alpha,
        horizontal_align=HorizontalAlign.RIGHT,
        background=False,
    )

    # ...

Checkpoint ​

Run the level and hit several Notes. The primary metric value and bar should update as Sonolus records each result.