Sonolus Wiki

18. SFX

In this chapter, we will add SFX to Note and Stage.

Effect Clips

Just like skin sprites, we need to declare which effect clips we want access to by referencing their names:

export const effect = defineEffect({
    clips: {
        stage: EffectClipName.Stage,
        perfect: EffectClipName.Perfect,
        great: EffectClipName.Great,
        good: EffectClipName.Good,
    },
})
export const effect = defineEffect({
    clips: {
        stage: EffectClipName.Stage,
        perfect: EffectClipName.Perfect,
        great: EffectClipName.Great,
        good: EffectClipName.Good,
    },
})

Note

To add SFX on judgment, we can check result judgment and call play on the correct effect clip.

Notice that play has a distance argument, which will prevent the effect clip from playing if it has previously played before the specified amount of time has passed. This is to prevent the same clip being played in quick succession and causing discomfort to player. In general, 0.02 is a good value.

export class Note extends Archetype {
    // ...
    touch() {
        // ...

        for (const touch of touches) {
            // ...

            switch (this.result.judgment) {
                case Judgment.Perfect:
                    effect.clips.perfect.play(0.02)
                    break
                case Judgment.Great:
                    effect.clips.great.play(0.02)
                    break
                case Judgment.Good:
                    effect.clips.good.play(0.02)
                    break
            }

            // ...
        }
    }

    // ...
}
export class Note extends Archetype {
    // ...
    touch() {
        // ...

        for (const touch of touches) {
            // ...

            switch (this.result.judgment) {
                case Judgment.Perfect:
                    effect.clips.perfect.play(0.02)
                    break
                case Judgment.Great:
                    effect.clips.great.play(0.02)
                    break
                case Judgment.Good:
                    effect.clips.good.play(0.02)
                    break
            }

            // ...
        }
    }

    // ...
}

Stage

Since we have judgment line react to tap already, it also makes sense to play SFX.

However, if a touch is used by a note, we shouldn't also play the stage SFX.

export class Stage extends Archetype {
    // ...

    touchOrder = 2
    touch() {
        for (const touch of touches) {
            if (!touch.started) continue
            if (isUsed(touch)) continue

            effect.clips.stage.play(0.02)
            return
        }
    }

    // ...
}
export class Stage extends Archetype {
    // ...

    touchOrder = 2
    touch() {
        for (const touch of touches) {
            if (!touch.started) continue
            if (isUsed(touch)) continue

            effect.clips.stage.play(0.02)
            return
        }
    }

    // ...
}