Skip to content

17 Life

In this chapter, we will set up life and secondary metric UI.

Configure Note Life Changes

Each play archetype can change the player's life for each judgment type.

In guide/lib/note.py, add level_life to the existing runtime import, then add an init_life helper beside init_score. The helper receives the Note archetype so it can configure that archetype's life changes. A Perfect judgment restores 10 life. A Miss deducts 100 life:

python
from sonolus.script.runtime import level_life, level_score


def init_life(note_class):
    note_class.archetype_life.update(
        perfect_increment=10,
        miss_increment=-100,
    )

Open guide/play/initialization.py and arrange the setup calls as shown, adding init_life(Note) after init_score(). The excerpt shows the changed imports and completed preprocess callback. Keep the other imports and class methods:

python
from guide.lib.note import init_life, init_score
from guide.play.note import Note


class Initialization(PlayArchetype):
    def preprocess(self):
        init_buckets()
        init_score()
        init_life(Note)
        init_ui()
        init_layout(1)

By default, life starts at its maximum of 1,000. The reward of 10 life has no effect while life is full, but it restores life after a loss. Reaching 0 marks the level as failed without ending the current play session.

Add a Consecutive Perfect Reward

Archetype life changes apply to individual Note results. The level life setting can also apply a global reward for consecutive judgments, regardless of archetype.

In the existing init_life helper, reward the player with 50 life after every 10 consecutive Perfects:

python
def init_life(note_class):
    # ...

    level_life().update(
        consecutive_perfect_increment=50,
        consecutive_perfect_step=10,
    )

Show Life

Use the secondary metric bar and value to display the player's life.

Select life explicitly as the secondary metric, again preserving the other UiConfig arguments:

python
from sonolus.script.ui import UiConfig, UiMetric


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

Then add the secondary metric layouts to init_ui in guide/lib/ui.py, immediately after ui.primary_metric_value.update(...):

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


def init_ui():
    ui = runtime_ui()

    # ...

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

    # ...

Checkpoint

Run the level, miss a Note, and then hit a Perfect. The secondary metric should lose 100 life for the Miss and regain 10 for the Perfect.