diff --git a/packages/frontend/src/pages/drop-and-fusion.vue b/packages/frontend/src/pages/drop-and-fusion.vue index df7856c377..d790d0f0e7 100644 --- a/packages/frontend/src/pages/drop-and-fusion.vue +++ b/packages/frontend/src/pages/drop-and-fusion.vue @@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
@@ -74,7 +74,7 @@ SPDX-License-Identifier: AGPL-3.0-only >
{{ comboPrev }} Chain!
-
+
-
+
SCORE:
@@ -103,6 +103,14 @@ SPDX-License-Identifier: AGPL-3.0-only
+
REPLAYING
+
+
+
+
+ END REPLAY +
+
@@ -140,7 +148,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- Restart + Retry
@@ -403,6 +411,7 @@ let viewScale = 1; let game: DropAndFusionGame; let containerElRect: DOMRect | null = null; let seed: string; +let logs: ReturnType | null = null; const containerEl = shallowRef(); const canvasEl = shallowRef(); @@ -459,6 +468,10 @@ function hold() { game.hold(); } +function retry() { + game.gameOver(); +} + function restart() { game.dispose(); gameOver.value = false; @@ -474,7 +487,6 @@ function restart() { function replay() { replaying.value = true; - const logs = game.getLogs(); game.dispose(); game = new DropAndFusionGame({ width: GAME_WIDTH, @@ -490,11 +502,17 @@ function replay() { } ), }); + attachGameEvents(); os.promiseDialog(game.load(), async () => { - game.start(logs); + game.start(logs!); }); } +function endReplay() { + replaying.value = false; + game.dispose(); +} + function attachGameEvents() { game.addListener('changeScore', value => { score.value = value; @@ -520,6 +538,8 @@ function attachGameEvents() { }); game.addListener('dropped', () => { + if (replaying.value) return; + dropReady.value = false; window.setTimeout(() => { if (!gameOver.value) { @@ -539,6 +559,8 @@ function attachGameEvents() { }); game.addListener('monoAdded', (mono) => { + if (replaying.value) return; + // 実績関連 if (mono.level === 10) { claimAchievement('bubbleGameExplodingHead'); @@ -551,6 +573,9 @@ function attachGameEvents() { }); game.addListener('gameOver', () => { + if (replaying.value) return; + + logs = game.getLogs(); currentPick.value = null; dropReady.value = false; gameOver.value = true; @@ -953,6 +978,28 @@ definePageMetadata({ } } +.replayIndicator { + position: absolute; + z-index: 10; + left: 10px; + bottom: 10px; + padding: 6px 8px; + color: #f00; + background: #0008; + border-radius: 6px; + pointer-events: none; +} + +.replayIndicatorText { + animation: replayIndicator-blink 2s infinite; +} + +@keyframes replayIndicator-blink { + 0% { opacity: 1; } + 50% { opacity: 0; } + 100% { opacity: 1; } +} + @keyframes currentMonoArrow { 0% { transform: translateY(0); } 25% { transform: translateY(-8px); } diff --git a/packages/frontend/src/scripts/drop-and-fusion-engine.ts b/packages/frontend/src/scripts/drop-and-fusion-engine.ts index e5aa3fbe93..e2327552f3 100644 --- a/packages/frontend/src/scripts/drop-and-fusion-engine.ts +++ b/packages/frontend/src/scripts/drop-and-fusion-engine.ts @@ -273,7 +273,7 @@ export class DropAndFusionGame extends EventEmitter<{ } } - private gameOver() { + public gameOver() { this.isGameOver = true; if (this.tickRaf) window.cancelAnimationFrame(this.tickRaf); this.tickRaf = null;