Sonolus Wiki

04. Note and Panel Count

In this chapter, we will setup Note and implement calculating panel count.

Note Archetype

Let's first set up Note:

export class Note extends Archetype {}
export class Note extends Archetype {}
export const archetypes = defineArchetypes({
    // ...
    Note,
})
export const archetypes = defineArchetypes({
    // ...
    Note,
})

Duration

If we know the duration, we can use it to calculate panel count.

How would we obtain the duration? A simple way is to have a variable storing the duration of a level, and update it as we visit notes.

Let's declare it, using Preview Data block:

export const chart = previewData({
    duration: Number,
})
export const chart = previewData({
    duration: Number,
})

Updating Duration

To calculate note's time, we need its beat from data. We can declare it just like in play mode:

export class Note extends Archetype {
    import = this.defineImport({
        beat: { name: EngineArchetypeDataName.Beat, type: Number },
    })
}
export class Note extends Archetype {
    import = this.defineImport({
        beat: { name: EngineArchetypeDataName.Beat, type: Number },
    })
}

In Note's preprocess callback, we can update duration to note's time if it's bigger:

export class Note extends Archetype {
    // ...

    preprocess() {
        chart.duration = Math.max(chart.duration, bpmChanges.at(this.import.beat).time)
    }
}
export class Note extends Archetype {
    // ...

    preprocess() {
        chart.duration = Math.max(chart.duration, bpmChanges.at(this.import.beat).time)
    }
}

Panel Count

We can now change panel count to calculate based on the duration:

export const panel = {
    // ...

    get count() {
        return Math.ceil(chart.duration / this.h)
    },
}
export const panel = {
    // ...

    get count() {
        return Math.ceil(chart.duration / this.h)
    },
}

Canvas

Last but not least, we need to make sure canvas size calculation code runs after all notes have finished updating duration.

We can move the code to Stage's preprocess and give it a higher order:

export class Stage extends Archetype {
    preprocessOrder = 1
    preprocess() {
        canvas.set({
            scroll: Scroll.LeftToRight,
            size: (panel.count * panel.w * screen.h) / 20,
        })
    }

    // ...
}
export class Stage extends Archetype {
    preprocessOrder = 1
    preprocess() {
        canvas.set({
            scroll: Scroll.LeftToRight,
            size: (panel.count * panel.w * screen.h) / 20,
        })
    }

    // ...
}