【ゲーム】JavaScript:01 タイピングゲーム

 このタイピングゲームは、60秒間に表示される日本語の単語をできるだけ多くタイプしてスコアを競うシンプルなミニゲームです。最初はひらがな/カタカナ混在の「easy」レベルから始まり、スコアに応じて「medium」「hard」と自動で難易度が上がっていきます。制限時間がゼロになると入力がロックされ、上位5回分のスコアランキングが表示されます。

ゲームの遊び方

 ページを読み込むと自動でゲームがスタートします。画面中央に表示された単語を入力ボックスに正確に入力するとスコアが+1され、次の単語がランダムに表示されます。10点で中級、20点で上級へと単語リストが切り替わります。残り時間が 0 秒になるとゲームオーバーとなり、メッセージで最終スコアを通知、ランキングが更新されます。「もう一度遊ぶ」ボタンでリトライできます。

🎮ゲームプレイ

以下のリンク先から実際にプレイできます。

01 タイピングゲーム

素材のダウンロード

以下のリンクから使用する素材をダウンロードできます。

typing_bg.png

ゲーム画面イメージ

プログラム全文(typing.html)

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>⌨️ タイピングゲーム 🎉</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: 'Arial', sans-serif;
            background-color: #4CAF50;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            color: #fff;
            font-size: 18px;
            background-image: url('typing_bg.png');
            background-size: cover;
            background-position: center;
        }
        .game-container {
            text-align: center;
            padding: 30px;
            background-color: rgba(0, 0, 0, 0.7);
            border-radius: 15px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
            width: 800px;
        }
        h1 { font-size: 2.5rem; margin-bottom: 20px; color: #FFEB3B; }
        #score, #timer { font-size: 1.5rem; margin-bottom: 15px; color: #FF4081; }
        #word-display { font-size: 2.5rem; margin: 20px 0; font-weight: bold; color: #03A9F4; }
        #input-box {
            font-size: 1.8rem;
            padding: 12px;
            width: 80%;
            border-radius: 8px;
            border: 2px solid #FFEB3B;
            outline: none;
            transition: all 0.3s ease;
        }
        #input-box:focus { border-color: #03A9F4; background-color: #222; color: #FFEB3B; }
        #game-message {
            font-size: 1.5rem;
            margin: 15px 0;
            color: #FFEB3B;
        }
        #ranking { margin-top: 20px; font-size: 1.2rem; color: #FFEB3B; }
        #restart-btn {
            margin-top: 20px;
            padding: 10px 20px;
            background-color: #FFEB3B;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 1.2rem;
            color: #222;
        }
        #restart-btn:hover { background-color: #FF9800; }
    </style>
</head>
<body>
    <div class="game-container">
        <h1>⌨️ タイピングゲーム 🎉</h1>
        <!-- スコア表示 -->
        <p id="score">スコア: 0</p>
        <!-- タイマー表示 -->
        <p id="timer">残り時間: 60秒</p>
        <!-- 現在の単語表示 -->
        <p id="word-display">--</p>
        <!-- 入力ボックス -->
        <input type="text" id="input-box" placeholder="タイプしてみよう!">
        <!-- ゲーム終了メッセージ表示エリア -->
        <p id="game-message"></p>
        <!-- ランキング表示エリア -->
        <div id="ranking"></div>
        <!-- 再スタートボタン -->
        <button id="restart-btn" onclick="restartGame()" style="display:none;">もう一度遊ぶ</button>
    </div>
    <script>
        // 日本語入力中かどうかのフラグ(composition イベント用)
        let isComposing = false;

        // 難易度別の単語リスト定義
        const easyWords = [
            "ねこ","イヌ","さかな","リンゴ","ぶどう","バナナ","メロン","くま","トリ","かに",
            "サクラ","うみ","ヤマ","たいよう","ツキ","はな","ミズ","そら","カゼ","あめ",
            "ユキ","ホシ","き","クツ","いえ","クルマ","でんしゃ","ネズミ","サル","りす"
        ];
        const mediumWords = [
            "コンピュータ","プログラミング","アニメーション","ミュージック","ドキュメンタリー","エンジニア",
            "クリエイター","デバッグ","アップデート","カレンダー","ともだち","せんせい","だいがく","かがく",
            "かいもの","すいえい","えいが","たんじょうび","コミュニケーション","インターネット","ネットワーク",
            "データベース","セキュリティ","インストール","バージョン","パフォーマンス","モチベーション",
            "コラボレーション","リファクタリング","アルゴリズム"
        ];
        const hardWords = [
            "サステナビリティ","インフレーション","オーケストレーション","マイクロプロセッサ","トランスフォーメーション",
            "ディスラプション","コンフィギュレーション","プロフェッショナル","アーキテクチャー","パラダイムシフト",
            "エクスペリエンス","エンベデッドシステム","サブスクリプション","リバースエンジニアリング","コンティンジェンシープラン",
            "ベンチマーキング","クロスプラットフォーム","ビジュアライゼーション","ミドルウェア","マルチスレッディング",
            "イノベーション","インフラストラクチャー","オーセンティケーション","アナリティクス","セマンティクス",
            "きょういくがくぶ","れんらくちょう","しゅうかんてんきよほう","こうつうあんぜんしゅうかん","じゆうけんきゅう"
        ];

        // ゲームの状態を保持する変数
        let score = 0;               // 現在のスコア
        let currentWord = "";        // 出題中の単語
        let timerValue = 60;         // 残り時間(秒)
        let timerInterval;           // setInterval の戻り値
        let ranking = [];            // スコアランキング配列
        let wordList = easyWords;    // 現在使用中の単語リスト

        // DOM要素取得
        const scoreElement   = document.getElementById("score");
        const timerElement   = document.getElementById("timer");
        const wordDisplay    = document.getElementById("word-display");
        const inputBox       = document.getElementById("input-box");
        const messageElement = document.getElementById("game-message");
        const rankingElement = document.getElementById("ranking");
        const restartBtn     = document.getElementById("restart-btn");

        // IME入力開始イベント:日本語入力中フラグを立てる
        inputBox.addEventListener("compositionstart", () => {
            isComposing = true;
        });
        // IME入力確定イベント:フラグを倒し、判定を行う
        inputBox.addEventListener("compositionend", () => {
            isComposing = false;
            checkTyping();
        });
        // 通常の入力イベント:日本語入力中でなければチェック
        inputBox.addEventListener("input", () => {
            if (!isComposing) checkTyping();
        });

        /**
         * ゲームを初期化して開始する
         */
        function startGame() {
            // 入力ボックス有効化&クリア
            inputBox.disabled = false;
            inputBox.value = "";
            // スコア・タイマー・単語リスト初期化
            score = 0;
            timerValue = 60;
            wordList = easyWords;
            updateWordList();
            // 最初の単語を生成
            generateWord();
            // UI更新
            scoreElement.textContent = `スコア: ${score}`;
            timerElement.textContent = `残り時間: ${timerValue}秒`;
            messageElement.textContent = "";
            rankingElement.innerHTML = "";
            restartBtn.style.display = "none";
            // タイマー開始
            startTimer();
        }

        /**
         * ランダムに単語を選んで表示
         */
        function generateWord() {
            const idx = Math.floor(Math.random() * wordList.length);
            currentWord = wordList[idx];
            wordDisplay.textContent = currentWord;
            inputBox.value = ""; // 入力欄クリア
        }

        /**
         * 入力内容が正解ならスコア加算&次の単語へ
         */
        function checkTyping() {
            if (inputBox.value === currentWord) {
                score++;
                scoreElement.textContent = `スコア: ${score}`;
                updateWordList();  // 難易度切り替え判定
                generateWord();    // 次の単語
            }
        }

        /**
         * スコアに応じて単語リストを切り替え
         */
        function updateWordList() {
            if (score >= 20) {
                wordList = hardWords;
            } else if (score >= 10) {
                wordList = mediumWords;
            } else {
                wordList = easyWords;
            }
        }

        /**
         * 1秒間隔でタイマーをカウントダウン
         */
        function startTimer() {
            clearInterval(timerInterval);
            timerInterval = setInterval(() => {
                timerValue--;
                timerElement.textContent = `残り時間: ${timerValue}秒`;
                // 時間切れ判定
                if (timerValue === 0) {
                    clearInterval(timerInterval);
                    gameOver();
                }
            }, 1000);
        }

        /**
         * ゲーム終了処理:入力無効化&メッセージ表示&ランキング更新
         */
        function gameOver() {
            // 入力欄を無効化
            inputBox.disabled = true;
            // スコアをランキングに追加・ソート
            ranking.push(score);
            ranking.sort((a, b) => b - a);
            if (ranking.length > 5) ranking.pop(); // 上位5件に制限
            // 終了メッセージ表示
            messageElement.textContent = `🎉 ゲーム終了!あなたのスコアは ${score} です。`;
            // ランキング表示
            rankingElement.innerHTML = "<h2>🏆 スコアランキング</h2>";
            ranking.forEach((s, i) => {
                rankingElement.innerHTML += `<p>順位 ${i+1}: ${s} 点</p>`;
            });
            // 再スタートボタン表示
            restartBtn.style.display = "inline-block";
        }

        /**
         * 「もう一度遊ぶ」ボタン押下時に再スタート
         */
        function restartGame() {
            startGame();
        }

        // ページ読み込み時にゲーム開始
        startGame();
    </script>
</body>
</html>

アルゴリズムの流れ

ステップ処理内容
ページ読み込みstartGame() を呼び出して初期化 → 単語表示 → タイマー開始
単語生成generateWord() が乱数で単語を選んで表示 → 入力欄クリア
入力チェックユーザーの入力が単語と一致したら checkTyping() → スコア更新&次単語へ
リスト更新updateWordList() でスコアに応じた難易度(easy/medium/hard)の切替
タイマー管理startTimer() で1秒ごとに残り時間をデクリメント → 0秒で gameOver()
ゲーム終了gameOver() で入力欄ロック → ランキング更新 → アラート表示 → リトライボタン表示
リスタート「もう一度遊ぶ」押下で restartGame()startGame()

ブラウザ組み込みの主な命令

命令/メソッド説明
addEventListenerinputcompositionstartcompositionend イベントを監視
Math.random()乱数生成 → 単語リストからランダムに選択
setInterval / clearIntervalタイマー処理の定期実行と停止
document.getElementByIdDOM 要素取得 → テキスト更新や属性変更で UI を動的制御
innerHTML / textContent要素の表示内容を更新
alert()ゲーム終了時にユーザーへ結果を通知
Array.sort()スコアランキング配列を降順ソート

関数の詳細

関数名役割・処理内容
startGame()ゲーム開始前の初期状態準備:・変数リセット(score, timerValue, wordList)・UI 更新(スコア・タイマー)・単語生成とタイマー起動・リトライボタン非表示
generateWord()現在の単語を更新:・wordList からランダム選択して currentWord にセット・単語表示要素と入力欄をクリア
checkTyping()入力チェック:・入力値と currentWord が完全一致したらスコア加算・スコア表示更新 → レベル切替 → 次単語生成
updateWordList()難易度調整:・スコア10点以上で中級リスト、20点以上で上級リストに切替
startTimer()タイマー管理:・既存タイマークリア → 1秒ごとに残り時間をデクリメント・0秒到達で gameOver() を呼び出し
gameOver()ゲーム終了処理:・入力欄ロック → 現スコアを ranking 配列へ追加・ソート・上位5件保持 → ランキング表示更新・アラート表示 → リトライボタン表示
restartGame()リスタート:・startGame() の呼び出し(初期化 → ゲーム再開)

改造のポイント

  • タイムリミットの調整timerValue = 60; を変更してプレイ時間を短縮/延長
  • 単語リストの拡張easyWordshardWords に好みの単語や英単語を追加
  • 難易度選択UIの追加:開始前にユーザーがレベルを選べるドロップダウンを実装
  • 効果音/BGM導入:正解時・終了時に new Audio('sound.mp3').play() を追加
  • スコアの永続化localStorage でランキングをブラウザ保存し、リロード後も持続
  • ビジュアル演出:残り10秒で背景色を変更、スコア獲得時にエフェクトを表示
  • モバイル最適化:タッチ操作への対応やフォントサイズの調整

以上のポイントを踏まえ、自分好みのタイピングゲームにカスタマイズしてみてください!