実現したいこと
- ショートカットキーを覚えてもらうタイピングゲームをJavaScriptで作成する
前提
勉強も兼ね、また職場でみんなにショートカットキーを覚えてもらおうと
簡単なゲームを作成したかったのですが、特定のショートカットキーを押すと
ショートカットキー本来の機能が反応してしまい、ゲームが成立しない状態に
なってしまっています。
発生している問題・エラーメッセージ
例えばF1キーなどを押したり、Ctrl+Wなどを押すと画面が切り替わってしまったり、 F11などでも音量が変わる(MACを使用しています)など、キー入力して場所を覚えて もらいたいのですが、ゲームが進行できなくなっています。
該当のソースコード
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Shortcut Typing Game</title> <style> #game-canvas { border: 1px solid #000; } #score-label, #time-label { display: inline-block; width: 70px; text-align: right; } #score, #time-left, #time-limit { display: inline-block; width: 50px; text-align: left; } #game-canvas { background-color: black; } </style> </head> <body> <canvas id="game-canvas" width="800" height="400"></canvas> <div> <span id="score-label">Score:</span> <span id="score">0</span> <span id="time-label">Time Left:</span> <span id="time-left">10</span> <span>/</span> <span id="time-limit">10</span> </div> <button id="start-btn">Start</button> <button id="stop-btn">Stop</button> <button id="restart-btn">Restart</button> <button id="reset-btn">Reset</button> <script> // ゲーム画面のcanvas要素を取得する let canvas = document.getElementById('game-canvas'); let ctx = canvas.getContext('2d'); // ゲーム画面の背景色を指定する ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height); // ショートカットリスト const shortcuts = [ { keyName: 'Ctrl+C', keyCode: 67, description: 'コピー' }, { keyName: 'Ctrl+X', keyCode: 88, description: '切り取り' }, { keyName: 'Ctrl+V', keyCode: 86, description: '貼り付け' }, { keyName: 'Ctrl+A', keyCode: 65, description: '全て選択' }, { keyName: 'Ctrl+Z', keyCode: 90, description: '元に戻す' }, { keyName: 'Ctrl+Y', keyCode: 89, description: 'やり直し' }, { keyName: 'Ctrl+F', keyCode: 70, description: '検索' }, { keyName: 'Ctrl+S', keyCode: 83, description: '保存' }, { keyName: 'Ctrl+N', keyCode: 78, description: '新規作成' }, { keyName: 'Ctrl+O', keyCode: 79, description: 'ファイルを開く' }, { keyName: 'Ctrl+P', keyCode: 80, description: '印刷' }, { keyName: 'Ctrl+Alt+Delete', keyCode: 46, description: 'タスクマネージャーを開く' }, { keyName: 'Ctrl+Tab', keyCode: 9, description: '次のタブに切り替える' }, { keyName: 'Ctrl+Shift+Tab', keyCode: 9, description: '前のタブに切り替える' }, { keyName: 'Ctrl+T', keyCode: 84, description: '新しいタブを開く' }, { keyName: 'Ctrl+W', keyCode: 87, description: '現在のタブを閉じる' }, { keyName: 'Ctrl+Shift+T', keyCode: 84, description: '最後に閉じたタブを復元する' }, { keyName: 'Ctrl+Shift+N', keyCode: 78, description: 'シークレットモードで新しいウィンドウを開く' }, { keyName: 'Alt+Tab', keyCode: 9, description: '別のアプリケーションに切り替える' }, { keyName: 'Alt+F4', keyCode: 115, description: 'アプリケーションを閉じる' }, { keyName: 'F1', keyCode: 112, description: 'ヘルプを表示する' }, { keyName: 'F2', keyCode: 113, description: 'ファイル名を変更する' }, { keyName: 'F5', keyCode: 116, description: 'リフレッシュ、再読み込み' }, { keyName: 'F11', keyCode: 122, description: 'フルスクリーン表示に切り替える' } ]; // 現在のショートカットを格納する変数 let currentShortcut = ''; // 得点を格納する変数 let score = 0; // 制限時間を格納する変数 let timeLimit = 10; // カウントダウンを行うinterval IDを格納する変数 let countdownInterval; // ゲーム中かどうかを示すフラグ let isPlaying = false; // ショートカットを表示する関数 function showShortcut() { // ショートカットリストからランダムにショートカットを選択する let index = Math.floor(Math.random() * shortcuts.length); currentShortcut = shortcuts[index]; // canvasに現在のショートカットを描画する ctx.clearRect(0,0,canvas.width,canvas.height);//まず消す ctx.fillStyle = '#f00'; ctx.fillRect(150, 150, 300, 100); ctx.font = '24px Arial'; ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.fillText(currentShortcut.keyName, 300, 200); ctx.fillText(currentShortcut.description, 300, 240); } // キー入力を受け取る関数 function handleKeyPress(event) { // ゲーム中でない場合は何もしない if (!isPlaying) { return; } // ここから追加 event.preventDefault(); // ここまで追加 if (event.keyCode === currentShortcut.keyCode) { // 得点を加算する score += 10; // スコアを更新する document.getElementById('score').textContent = score; // 次のショートカットを表示する showShortcut(); } } // ゲームを開始する関数 function startGame() { score = 0; // スタートボタンを無効化する document.getElementById('start-btn').disabled = true; // 制限時間を表示する document.getElementById('time-limit').textContent = timeLimit; timeLimit = 10; // 得点を表示する document.getElementById('score').textContent = score; // ゲーム中フラグを立てる isPlaying = true; // カウントダウンを開始する countdownInterval = setInterval(() => { timeLimit--; document.getElementById('time-limit').textContent = timeLimit; // 制限時間が0になった場合はゲームを終了する if (timeLimit === 0) { endGame(); } }, 1000); //最初のショートカットを表示する showShortcut(); // キー入力を受け取るようにする document.addEventListener('keydown', handleKeyPress); } // ゲームを終了する関数 function endGame() { // カウントダウンを停止する clearInterval(countdownInterval); // ゲーム中フラグを下ろす isPlaying = false; // canvasをクリアする ctx.clearRect(0, 0, canvas.width, canvas.height); // canvasに得点を描画する ctx.font = '48px Arial'; ctx.fillStyle = '#f00'; ctx.textAlign = 'center'; ctx.fillText(`Score: ${score}`, 300, 200); // スタートボタンを有効化する document.getElementById('start-btn').disabled = false; } // ストップボタンをクリックした時の処理 function stopGame() { // ゲーム中でなければ何もしない if (!isPlaying) { return; } // スタートボタンを有効化する document.getElementById('start-btn').disabled = false; // キー入力を受け取るイベントリスナーを削除する document.removeEventListener('keydown', handleKeyPress); // カウントダウンを停止する clearInterval(countdownInterval); // ゲーム中フラグを下ろす isPlaying = false; } // リスタートボタンをクリックした時の処理 function restartGame() { stopGame(); // スタートボタンを有効化する document.getElementById('start-btn').disabled = false; score = 0; document.getElementById('score').textContent = score; timeLimit = 10; document.getElementById('time-limit').textContent = timeLimit; } // リセットボタンをクリックした時の処理 function resetGame() { restartGame(); showShortcut(); } // 各ボタンにイベントリスナーを登録する document.getElementById('start-btn').addEventListener('click', startGame); document.getElementById('stop-btn').addEventListener('click', stopGame); document.getElementById('restart-btn').addEventListener('click', restartGame); document.getElementById('reset-btn').addEventListener('click', resetGame); document.addEventListener('keydown', function(event) { event.preventDefault(); }); </script> </body> </html>
試したこと
event.preventDefault(); で制限をかけることができるのではと思い
追加してみましたが、どうも限界があるようです。
補足情報(FW/ツールのバージョンなど)
JavaScriptでは限界があるようなら一旦諦めて、別の機会に作るか、
選択クイズ(正しいキーはどれでしょう:4択)のようなクイズゲームに
切り替えも検討していますが、もしショートカットキーのキー入力が行われたかどうかを
ゲーム内だけで反映させ、実際の動作はしないようにする方法があればご教示いただきたいです。
よろしくお願いいたします。