マガジン

タイピングゲームの作り方:入力判定とローマ字対応

遊びをつくる

執筆にClaudeを使用しています。

キーボードとタッチの二つの入力が、同じ駒のジャンプにつながる様子を描いたイラスト。
記事のテーマをもとに制作したAI生成イラスト。

タイピングゲームを自作しようとしたとき、最初に壁になるのは「入力判定をどう書くか」です。画面に「か」と表示して、プレイヤーが「ka」と打ったら正解にする——この一文で言えることが、コードにすると意外に複雑になります。ひらがな1文字に対して複数のローマ字表記が存在し、さらに「っ」や「ん」のような例外も絡んでくるからです。 この記事では、ブラウザで動くタイピングゲームを作るうえで必要な入力判定の設計と、ローマ字変換テーブルの組み方を具体的に説明します。JavaScriptで書く前提ですが、考え方の部分はどの言語にも応用できます。

この記事の目次
  1. 入力判定の設計:「完全一致」ではなく「前方一致」で進める
  2. ローマ字変換テーブルの作り方と複数表記の扱い
  3. 「っ」「ん」「ぁ」など例外文字の処理
  4. お題テキストの分解とゲームループの組み立て
  5. 完成度を上げる判断基準:何を入れて何を後回しにするか
  6. 次の行動

入力判定の設計:「完全一致」ではなく「前方一致」で進める

タイピングゲームの入力判定は「打ち終わったら正解・不正解を判定する」のではなく、「1文字打つたびに途中経過を評価する」方式が標準です。この方式を前方一致判定と呼びます。

たとえばお題が「ka」のとき、プレイヤーが「k」を打った段階で「まだ完成していないが正しい方向に進んでいる」と判断します。次に「a」が来れば正解、「i」が来れば誤りです。この判断を毎キーストロークで行うことで、打ち間違えた瞬間に赤く光るようなフィードバックが実現できます。

実装の骨格はシンプルです。現在の入力バッファ(打ったキーの積み上げ)と、お題のローマ字表記を比較します。バッファが表記の先頭部分と一致し続けている間は「入力中」、バッファが表記と完全一致したら「正解」、一致しなくなった瞬間は「誤入力」です。

入力バッファ: "k"
お題:        "ka"
→ 前方一致 → 継続

入力バッファ: "ka"
お題:        "ka"
→ 完全一致 → 正解

入力バッファ: "ki"
お題:        "ka"
→ 不一致   → 誤入力

誤入力のときはバッファをリセットするか、1文字だけ削除するかを設計で決めます。リセット方式は実装が簡単で、削除方式はプレイヤーに優しい反面、バックスペースの扱いを別途考える必要があります。

ローマ字変換テーブルの作り方と複数表記の扱い

ひらがなとローマ字の対応は、辞書オブジェクトとして持つのが一般的です。最小構成は次のような形になります。

js
const romajiMap = {
  "あ": ["a"],
  "い": ["i", "yi"],
  "う": ["u", "wu", "whu"],
  "か": ["ka", "ca"],
  "き": ["ki"],
  "く": ["ku", "cu", "qu"],
  "し": ["si", "shi", "ci"],
  "ち": ["ti", "chi"],
  "つ": ["tu", "tsu"],
  "ふ": ["hu", "fu"],
  // …
};

1文字に複数の表記がある場合、入力判定は「いずれか1つに前方一致すれば継続」と考えます。プレイヤーが「s」を打ったとき、「si」でも「shi」でも受け付けるわけです。

ただし「sh」まで打った時点で「si」は候補から外れます。これを候補絞り込み方式といいます。実装では、現在のバッファに前方一致する候補だけを残していき、候補が0になれば誤入力と判定します。

js
function getActiveCandidates(buffer, candidates) {
  return candidates.filter(c => c.startsWith(buffer));
}

お題が複数のひらがなからなる場合は、文字ごとに候補を切り替えます。1文字分の候補のどれかが完全一致したら次の文字に進み、バッファをリセットします。

「っ」「ん」「ぁ」など例外文字の処理

特殊なひらがなは個別に対応が必要です。

促音「っ」

「っ」の入力方法は2種類あります。「ltu」「ltsu」「xtu」のように直接入力する方法と、次の子音を2回打つ方法です。「っか」なら「kka」と入力できます。これは「っ」単体ではなく「っ+次の文字」のセットで処理する必要があります。

実装方針:「っ」を処理するとき、次のひらがなの候補を先読みし、その子音1文字(「ka」なら「k」)を「っ」の入力候補の一つとして加えます。「k」が入力されたら「っ」を消費してバッファを「k」の状態で次の文字に進めます。

撥音「ん」

「ん」は「nn」「n'」(アポストロフィ)で打てますが、「na・ni・nu・ne・no」以外の文字が続く場合は「n」1文字だけでも「ん」として確定させるルールが一般的です。「んか」なら「n」の後に「k」が来たとき「ん」確定→「k」を次のバッファに引き継ぎます。ただし「na」などが続く場合は「n」単体では確定できないので、次のキー入力まで判断を保留します。

小文字(ぁ・ぃ・ぅ・ぇ・ぉ・ゃ・ゅ・ょ)

「きゃ」のような拗音は、セットで1単位として変換テーブルに登録するのが確実です。

js
const romajiMap = {
  "きゃ": ["kya"],
  "きゅ": ["kyu"],
  "きょ": ["kyo"],
  "しゃ": ["sha", "sya"],
  // …
};

お題のひらがな列を処理するとき、2文字の組み合わせを1文字の組み合わせより先に照合するようにすれば、自然に拗音が優先されます。

お題テキストの分解とゲームループの組み立て

ゲーム全体の流れを整理します。

  1. お題文字列を受け取る(例:「さくら」)
  2. ひらがな列に分解する(「さ」「く」「ら」)。拗音を含む場合は2文字組み合わせを先に確認する
  3. 現在の文字インデックスを0にして、その文字の変換候補を取得する
  4. keydownイベントでキーを受け取る。event.keyを使うとキーボードレイアウトに依存しにくい
  5. 前方一致判定。候補が残れば継続、完全一致すれば次の文字へ進む、候補が0になれば誤入力処理
  6. すべての文字を消化したらゲームクリア

keydownを使う際の注意点として、日本語IMEが有効になっているとキーイベントが正常に取得できないことがあります。event.isComposingがtrueのときはIME変換中なのでイベントを無視するのが一般的な対策です。また、タイピングゲームでは通常のテキスト入力欄(<input>)を使わず、ドキュメント全体やゲーム用のdivでkeydownを受け取る設計にすると、IMEが介入しにくくなります。

表示の更新は、現在のバッファをお題のローマ字候補と重ね合わせてグレー(未入力)と色つき(入力済み)で出し分けると、プレイヤーに残り入力が伝わります。候補が複数ある場合はどれを表示するかを決める必要がありますが、最も短い候補を優先表示するのがよく使われる方針です。

完成度を上げる判断基準:何を入れて何を後回しにするか

最小限のタイピングゲームに必要な要素と、後回しにできる要素を分けて考えると開発が進みやすくなります。

最初に作る(必須)

  • ひらがな→ローマ字の変換テーブル(よく使う文字のみでも可)
  • 前方一致判定と誤入力検出
  • 1単語が打ち終わったら次の単語へ進む処理

動いてから追加する(任意)

  • 「っ」の子音2連打対応
  • 「ん」の自動確定
  • タイムアタックやスコア計算
  • 打鍵音・アニメーション

変換テーブルはゼロから書くと漏れが出やすいので、既存のオープンソースライブラリ(MIT等のライセンスのもの)を参照してテーブル部分だけ借用し、判定ロジックは自分で書く、という分担も現実的です。ライセンス条件は利用前に必ず原文で確認してください。

次の行動

まず「あいうえお」だけに絞った変換テーブルと前方一致判定を動かし、1単語が打てる最小のゲームを完成させてください。そこから拗音・促音・「ん」と順に範囲を広げていくと、つまずきポイントが1か所に絞られて対処しやすくなります。作ったゲームはHTMLファイルまたはZIPとしてアソバースに投稿して、実際のプレイヤーからフィードバックをもらいましょう。