Sonolus Wiki

10. 回放

在本章中,我们将实现音符回放逻辑。

判定与精确度

回放在观看模式中再现了一次被记录的游玩过程。

为了实现这个功能,我们需要判定与精确度信息:

export class Note extends Archetype {
    // ...

    import = this.defineImport({
        // ...
        judgment: { name: EngineArchetypeDataName.Judgment, type: DataType<Judgment> },
        accuracy: { name: EngineArchetypeDataName.Accuracy, type: Number },
    })

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

    import = this.defineImport({
        // ...
        judgment: { name: EngineArchetypeDataName.Judgment, type: Number },
        accuracy: { name: EngineArchetypeDataName.Accuracy, type: Number },
    })

    // ...
}

销毁时间

我们可以根据我们的精确度来调整销毁时间:

export class Note extends Archetype {
    // ...

    despawnTime() {
        return replay.isReplay
            ? timeScaleChanges.at(this.targetTime + this.import.accuracy).scaledTime
            : this.visualTime.max
    }

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

    despawnTime() {
        return replay.isReplay
            ? timeScaleChanges.at(this.targetTime + this.import.accuracy).scaledTime
            : this.visualTime.max
    }

    // ...
}

音效

类似地,我们可以根据判定与精确度调整音效:

export class Note extends Archetype {
    // ...

    preprocess() {
        // ...

        if (replay.isReplay) {
            const hitTime = this.targetTime + this.import.accuracy

            switch (this.import.judgment) {
                case Judgment.Perfect:
                    effect.clips.perfect.schedule(hitTime, 0.02)
                    break
                case Judgment.Great:
                    effect.clips.great.schedule(hitTime, 0.02)
                    break
                case Judgment.Good:
                    effect.clips.good.schedule(hitTime, 0.02)
                    break
            }
        } else {
            effect.clips.perfect.schedule(this.targetTime, 0.02)
        }

        // ...
    }

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

    preprocess() {
        // ...

        if (replay.isReplay) {
            const hitTime = this.targetTime + this.import.accuracy

            switch (this.import.judgment) {
                case Judgment.Perfect:
                    effect.clips.perfect.schedule(hitTime, 0.02)
                    break
                case Judgment.Great:
                    effect.clips.great.schedule(hitTime, 0.02)
                    break
                case Judgment.Good:
                    effect.clips.good.schedule(hitTime, 0.02)
                    break
            }
        } else {
            effect.clips.perfect.schedule(this.targetTime, 0.02)
        }

        // ...
    }

    // ...
}

粒子效果

最后,如果玩家并没有击打到音符,我们应该跳过播放粒子效果:

export class Note extends Archetype {
    // ...

    terminate() {
        // ...
        if (replay.isReplay && !this.import.judgment) return

        // ...
    }

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

    terminate() {
        // ...
        if (replay.isReplay && !this.import.judgment) return

        // ...
    }

    // ...
}