diff --git a/src/en/replay/index.html b/src/en/replay/index.html
index bae376a7..122bd1f6 100644
--- a/src/en/replay/index.html
+++ b/src/en/replay/index.html
@@ -68,6 +68,22 @@
+
+
+
+
Enter
+
↑
+
←
+
↓
+
→
+
+
+
+
+
+ Show
+ Hide
▶
❚❚
diff --git a/src/ko/replay/index.html b/src/ko/replay/index.html
index 1d5a502c..12590fc9 100644
--- a/src/ko/replay/index.html
+++ b/src/ko/replay/index.html
@@ -65,6 +65,22 @@
+
+
+
+
Enter
+
↑
+
←
+
↓
+
→
+
+
+
+
+
+ 보기
+ 숨기기
▶
❚❚
diff --git a/src/resources/js/replay/pikavolley_replay.js b/src/resources/js/replay/pikavolley_replay.js
index 5a2ffaaa..93a1ae9e 100644
--- a/src/resources/js/replay/pikavolley_replay.js
+++ b/src/resources/js/replay/pikavolley_replay.js
@@ -9,7 +9,11 @@ import {
import { Cloud, Wave } from '../offline_version_js/cloud_and_wave.js';
import { PikaPhysics } from '../offline_version_js/physics.js';
import { convert5bitNumberToUserInput } from '../utils/input_conversion.js';
-import { noticeEndOfReplay, moveScrubberTo } from './ui_replay.js';
+import {
+ noticeEndOfReplay,
+ moveScrubberTo,
+ showKeyboardInputs,
+} from './ui_replay.js';
import { setTickerMaxFPSAccordingToNormalFPS } from './replay_player.js';
/** @typedef GameState @type {function():void} */
@@ -236,6 +240,7 @@ export class PikachuVolleyballReplay extends PikachuVolleyball {
this.player2Keyboard.xDirection = player2Input.xDirection;
this.player2Keyboard.yDirection = player2Input.yDirection;
this.player2Keyboard.powerHit = player2Input.powerHit;
+ showKeyboardInputs(player1Input, player2Input);
let options = this.options[this.optionsCounter];
while (options && options[0] === this.replayFrameCounter) {
diff --git a/src/resources/js/replay/ui_replay.js b/src/resources/js/replay/ui_replay.js
index dd2fb441..73bfd9e0 100644
--- a/src/resources/js/replay/ui_replay.js
+++ b/src/resources/js/replay/ui_replay.js
@@ -1,6 +1,8 @@
import { replayPlayer } from './replay_player.js';
import '../../style.css';
+/** @typedef {import('../offline_version_js/physics.js').PikaUserInput} PikaUserInput */
+
let pausedByBtn = false;
const scrubberRangeInput = document.getElementById('scrubber-range-input');
@@ -189,6 +191,23 @@ export function setUpUI() {
noticeBoxFileErrorOKBtn.addEventListener('click', () => {
location.reload();
});
+
+ const keyboardContainer = document.getElementById('keyboard-container');
+ const showHideKeyboardBtn = document.getElementById('show-hide-keyboard-btn');
+ const showOrHideSpan = document.getElementById('show-or-hide-span');
+ showHideKeyboardBtn.addEventListener('click', () => {
+ if (!keyboardContainer.classList.contains('hidden')) {
+ keyboardContainer.classList.add('hidden');
+ showOrHideSpan.textContent = document.getElementById(
+ 'show-text'
+ ).textContent;
+ } else {
+ keyboardContainer.classList.remove('hidden');
+ showOrHideSpan.textContent = document.getElementById(
+ 'hide-text'
+ ).textContent;
+ }
+ });
}
export function adjustPlayPauseBtnIcon() {
@@ -255,6 +274,109 @@ export function showTotalTimeDuration(timeDuration) {
);
}
+/**
+ * Show Keyboard inputs
+ * @param {PikaUserInput} player1Input
+ * @param {PikaUserInput} player2Input
+ */
+export function showKeyboardInputs(player1Input, player2Input) {
+ const zKey = document.getElementById('z-key');
+ const rKey = document.getElementById('r-key');
+ const vKey = document.getElementById('v-key');
+ const dKey = document.getElementById('d-key');
+ const gKey = document.getElementById('g-key');
+
+ const enterKey = document.getElementById('enter-key');
+ const upKey = document.getElementById('up-key');
+ const downKey = document.getElementById('down-key');
+ const leftKey = document.getElementById('left-key');
+ const rightKey = document.getElementById('right-key');
+
+ function pressKeyElm(keyElm) {
+ if (!keyElm.classList.contains('pressed')) {
+ keyElm.classList.add('pressed');
+ }
+ }
+
+ function unpressKeyElm(keyElm) {
+ keyElm.classList.remove('pressed');
+ }
+
+ switch (player1Input.xDirection) {
+ case 0:
+ unpressKeyElm(dKey);
+ unpressKeyElm(gKey);
+ break;
+ case -1:
+ pressKeyElm(dKey);
+ unpressKeyElm(gKey);
+ break;
+ case 1:
+ unpressKeyElm(dKey);
+ pressKeyElm(gKey);
+ break;
+ }
+ switch (player1Input.yDirection) {
+ case 0:
+ unpressKeyElm(rKey);
+ unpressKeyElm(vKey);
+ break;
+ case -1:
+ pressKeyElm(rKey);
+ unpressKeyElm(vKey);
+ break;
+ case 1:
+ unpressKeyElm(rKey);
+ pressKeyElm(vKey);
+ break;
+ }
+ switch (player1Input.powerHit) {
+ case 0:
+ unpressKeyElm(zKey);
+ break;
+ case 1:
+ pressKeyElm(zKey);
+ break;
+ }
+
+ switch (player2Input.xDirection) {
+ case 0:
+ unpressKeyElm(leftKey);
+ unpressKeyElm(rightKey);
+ break;
+ case -1:
+ pressKeyElm(leftKey);
+ unpressKeyElm(rightKey);
+ break;
+ case 1:
+ unpressKeyElm(leftKey);
+ pressKeyElm(rightKey);
+ break;
+ }
+ switch (player2Input.yDirection) {
+ case 0:
+ unpressKeyElm(upKey);
+ unpressKeyElm(downKey);
+ break;
+ case -1:
+ pressKeyElm(upKey);
+ unpressKeyElm(downKey);
+ break;
+ case 1:
+ unpressKeyElm(upKey);
+ pressKeyElm(downKey);
+ break;
+ }
+ switch (player2Input.powerHit) {
+ case 0:
+ unpressKeyElm(enterKey);
+ break;
+ case 1:
+ pressKeyElm(enterKey);
+ break;
+ }
+}
+
export function enableReplayScrubberAndBtns() {
// @ts-ignore
scrubberRangeInput.disabled = false;
diff --git a/src/resources/style.css b/src/resources/style.css
index b1351b67..6fa2d367 100644
--- a/src/resources/style.css
+++ b/src/resources/style.css
@@ -601,3 +601,56 @@ label.custom-file-upload {
.disable-dbl-tap-zoom {
touch-action: manipulation;
}
+.flex-for-keyboard {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+ margin-top: 10px;
+}
+.grid-for-keyboard {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+ grid-template-rows: 1fr 1fr;
+ gap: 5px;
+ width: calc(5 * var(--btn-height));
+ height: calc(2.3 * var(--btn-height));
+}
+#z-key,
+#enter-key {
+ grid-row-start: 1;
+ grid-column-start: 1;
+}
+#r-key,
+#up-key {
+ grid-row-start: 1;
+ grid-column-start: 3;
+}
+#d-key,
+#left-key {
+ grid-row-start: 2;
+ grid-column-start: 2;
+}
+#v-key,
+#down-key {
+ grid-row-start: 2;
+ grid-column-start: 3;
+}
+#g-key,
+#right-key {
+ grid-row-start: 2;
+ grid-column-start: 4;
+}
+.keyboard-key {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 2px solid rgb(50, 50, 50);
+}
+.keyboard-key.pressed {
+ background-color: rgb(255, 0, 0);
+ color: white;
+}
+#show-hide-keyboard-btn {
+ font-size: calc(var(--font-size) / 1.3);
+ width: var(--btn-width);
+}