Skip to content

10 Replay

In this chapter, we will implement replay logic of Note.

Judgment and Accuracy

Replay recreates the recorded gameplay in watch mode.

In order to achieve that, we need the judgment and accuracy information:

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

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

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

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

    // ...
}

Despawn Time

We accuracy, we can adjust despawn time accordingly:

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

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

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

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

    // ...
}

SFX

Similarly, we can adjust SFX based on both judgment and accuracy:

TypeScript
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)
        }

        // ...
    }

    // ...
}
JavaScript
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)
        }

        // ...
    }

    // ...
}

Particle Effect

Lastly, we should skip playing particle effect if player did not hit the note:

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

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

        // ...
    }

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

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

        // ...
    }

    // ...
}