Sonolus Wiki

05. 音符绘制

在本章中,我们将实现音符原型的绘制逻辑。

声明

声明将使用的音符皮肤精灵:

export const skin = defineSkin({
    sprites: {
        // ...
        note: SkinSpriteName.NoteHeadCyan,
    },
})
export const skin = defineSkin({
    sprites: {
        // ...
        note: SkinSpriteName.NoteHeadCyan,
    },
})

屏幕缩放

与游玩模式不同,在预览模式中,我们已经修改了屏幕坐标系来使用不同的 X 与 Y 轴缩放。

为了正确绘制音符,我们需要提供长度和宽度缩放参数:

export const scaledScreen = {
    wToH: panel.h / 20,
}
export const scaledScreen = {
    wToH: panel.h / 20,
}

计算坐标

使用面板参数,我们可以计算在特定时间的坐标。

export const panel = {
    // ...

    getX(time: number) {
        return Math.floor(time / this.h) * this.w
    },

    getY(time: number) {
        return time % this.h
    },

    getPos(time: number) {
        return new Vec(this.getX(time), this.getY(time))
    },
}
export const panel = {
    // ...

    getX(time) {
        return Math.floor(time / this.h) * this.w
    },

    getY(time) {
        return time % this.h
    },

    getPos(time) {
        return new Vec(this.getX(time), this.getY(time))
    },
}

绘制

有了上述所有前提后,我们可以在正确的位置绘制正确大小的音符精灵:

export class Note extends Archetype {
    // ...

    render() {
        const time = bpmChanges.at(this.import.beat).time
        const pos = panel.getPos(time)

        const layout = Rect.one.mul(options.noteSize).scale(1, scaledScreen.wToH).add(pos)
        const z = 1000 - time

        skin.sprites.note.draw(layout, z, 1)
    }
}
export class Note extends Archetype {
    // ...

    render() {
        const time = bpmChanges.at(this.import.beat).time
        const pos = panel.getPos(time)

        const layout = Rect.one.mul(options.noteSize).scale(1, scaledScreen.wToH).add(pos)
        const z = 1000 - time

        skin.sprites.note.draw(layout, z, 1)
    }
}