Sonolus Wiki

20. 倍速

在本章中,我们将为音符添加倍速。

倍速

倍速是很多节奏类游戏的共同特征,它的另一个名字是 soflan。我们将实现倍速,更具体地说,倍速可以让整个游戏减速/加速。

由于倍速很流行,Sonolus 也提供了方便的函数来处理倍速。

倍速变化

与 BPM 变化类似,倍速变化也有一个特殊的原型名称,以及倍速值的特殊原型数据名称。让我们在测试关卡中添加一个倍速变化列表:

export const data: LevelData = {
    // ...
    entities: [
        // ...

        ...chart.timeScales.map(({ beat, timeScale }) => ({
            archetype: EngineArchetypeName.TimeScaleChange,
            data: [
                {
                    name: EngineArchetypeDataName.Beat,
                    value: beat,
                },
                {
                    name: EngineArchetypeDataName.TimeScale,
                    value: timeScale,
                },
            ],
        })),

        // ...
    ],
}
export const data = {
    // ...
    entities: [
        // ...

        ...chart.timeScales.map(({ beat, timeScale }) => ({
            archetype: EngineArchetypeName.TimeScaleChange,
            data: [
                {
                    name: EngineArchetypeDataName.Beat,
                    value: beat,
                },
                {
                    name: EngineArchetypeDataName.TimeScale,
                    value: timeScale,
                },
            ],
        })),

        // ...
    ],
}

音符

要为音符实现倍速,我们只需要将所有与渲染相关的逻辑更改为使用倍速时间。

请注意,我们没有更改与输入相关的逻辑,因为即使开启倍速,也应保持原始的视觉特征,不应影响输入的处理方式。

export class Note extends Archetype {
    // ...

    preprocess() {
        // ...

        this.visualTime.max = timeScaleChanges.at(this.targetTime).scaledTime
        // ...
    }

    // ...

    shouldSpawn() {
        return time.scaled >= this.spawnTime
    }

    // ...

    updateParallel() {
        // ...

        const y = Math.unlerp(this.visualTime.min, this.visualTime.max, time.scaled)

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

    preprocess() {
        // ...

        this.visualTime.max = timeScaleChanges.at(this.targetTime).scaledTime
        // ...
    }

    // ...

    shouldSpawn() {
        return time.scaled >= this.spawnTime
    }

    // ...

    updateParallel() {
        // ...

        const y = Math.unlerp(this.visualTime.min, this.visualTime.max, time.scaled)

        // ...
    }
}