タイピングゲームを作ってみよう
前回までで、JavaScriptでキーボード入力を受け付ける方法について学びました。 このページではその機能を利用して、簡単なタイピングゲームを作ってみたいと思います。
タイピングゲームといっても無数にあるので、本当に簡単なものにしたいと思います (本分はJavaScriptの勉強なので)。 ここではA~Zまでの文字をランダムに200文字表示して、 その入力速度を計ってみることにします。
このページのスクリプトを理解できれば、 もっと複雑で高性能なタイピングゲームも作れるようになるでしょう。 是非じっくりと読んで理解していってください。
タイピングゲーム作成の流れ
タイピングゲームを作るために、以下の流れに従ってスクリプトを組んでみることにしましょう。
問題を出題
- A-Zの文字を配列Mojiに格納します。
- 文字に対応するキーコードを、配列KCodeを作成して格納します。
- 0~25までの乱数を200個作成して、配列RNDに格納します。
- 何問目かをカウントする変数cntに、0を代入します。
- 出題枠にinnerHTMLで、A-Zの文字をランダムに200文字表示します。
最初にキーボード入力された時
- キー入力があると、キーコードを取得します。
- 取得したキーコードが問題文先頭文字のキーコードと同じか確認します。
- 同じ場合、現在時刻を取得して、変数TYPStartに格納します。
- 変数cntを+1します。
- innnerHTMLで、出題枠の最初の文字を削って199文字を表示し直します。
キーボード入力の続きと終了
- キー入力がある度に、キーコードを取得します。
- 取得したキーコードが問題文先頭文字のキーコードと同じか確認します。
- 同じならcntを+1します。
- cntが200になったら、現在の時間を取得して変数TYPEndに格納します。
- TYPEnd-TYPStartで掛かった時間を計算します。
- innerHTMLで問題枠に「GAME終了」と『時間』を表示します。
- cntが200未満なら、先頭文字を削除し、innerHTMLで問題文を書き直します。
タイピングゲームのスクリプト
以下のスクリプトをHTMLのヘッダーに記入してみてください。 今回は解説は殆どしていませんので、スクリプト中のコメントを参考になさってください。
<script type="text/javascript"> <!-- document.onkeydown = TYPE; //キー押下時に関数TYPE()を呼び出す //文字を格納する配列 var Moji = new Array("A","B","C","D","E","F","G","H","I", "J","K","L","M","N","O","P","Q","R", "S","T","U","V","W","X","Y","Z"); //キーコードを格納する配列 var KCode = new Array(65,66,67,68,69,70,71,72,73, 74,75,76,77,78,79,80,81,82, 83,84,85,86,87,88,89,90); //0~25までの乱数を格納する配列 var RND = new Array(); //グローバル変数群 var Mondai = ""; //問題の文字列を格納 var cnt=0; //何問目か格納 var TYPStart,TYPEnd; //開始時と終了時の時刻を格納 //0~25までの乱数を200個作成して配列RNDに格納する関数 function Ransu() { for ( i = 0 ; i < 200 ; i++ ) { RND[i] = Math.floor( Math.random() * 26 ); } } //タイピングゲームの問題をセットする関数 function GameSet() { //問題文とカウント数をクリアする Mondai=""; cnt=0; //乱数作成関数の呼び出し Ransu(); //問題文の作成(配列Mojiの要素をランダムに200文字繋げる) //Mondai= "" + Moji[RND[0]] + Moji[RND[1]] + … + Moji[RND[199]]となる for ( i = 0 ; i < 200 ; i++) { Mondai = Mondai + Moji[ RND[i] ]; } //問題枠に表示する document.getElementById("Waku").innerHTML = Mondai; } //キー入力を受け取る関数 function TYPE(evt) { var KC; //入力されたキーコードを格納する変数 //入力されたキーのキーコードを取得 if (document.all) { KC = event.keyCode; } else { KC = evt.which; } //入力されたキーコードと、問題文のキーコードを比較 if (KC == KCode[ RND[cnt] ]) { //以下、キーコードが一致した時の処理 //最初の1文字が入力された時間を記録する if (cnt==0) { TYPStart = new Date(); } cnt++; //カウント数を+1にする //全文字入力したか確認 if ( cnt < 200) { //問題文の頭の一文字を切り取る Mondai = Mondai.substring(1,Mondai.Length); //問題枠に表示する document.getElementById("Waku").innerHTML = Mondai; } else { //全文字入力していたら、終了時間を記録する TYPEnd = new Date(); //終了時間-開始時間で掛かったミリ秒を取得する var Keika = TYPEnd - TYPStart; //1000で割って「切捨て」、秒数を取得 var Sec = Math.floor( Keika/1000 ); //1000で割った「余り(%で取得できる)」でミリ秒を取得 var MSec = Keika % 1000; //問題終了を告げる文字列を作成 var Owari="GAME終了 時間:"+Sec+"秒"+MSec; //問題枠にゲーム終了を表示 document.getElementById("Waku").innerHTML = Owari; } } } // --> </script>
そしてbodyタグのonloadイベントで、 関数GameSet()を呼び出して問題を出題させます。 BODY内にはid名「Waku」を付けたdivタグ(pタグやtdタグ等も可)を一つ作っておきます。
<body onload="GameSet()"> <div id="Waku"></div>
上記スクリプトのサンプルです。出題枠はCSSで少し装飾しています。詳しくはソースを覗いてみて下さい。
スクリプトの補足
上記スクリプトで少しだけ補足しておきましょう。配列RNDは0~25のランダムな数字が入っています。 仮にRND[0]=3だとすると、Moji[RND[0]]="D",KCode[RND[0]]=68となります。 キーボードのDを押された時のキーコードは68なので、問題文と対応しているわけです。 RND[n]のnの値が何になろうと、Moji[RND[n]]のキーコードはKCode[RND[n]]なのです。
仮に今10文字入力したとしましょう。そうすると問題文は先頭から10文字削除されています。 ということで先頭はMoji[RND[10]]が表示されています。 それに対応するキーコードはKCode[RND[10]]になります。
では10の替わりに変数cntに置き換えるとどうでしょうか? 現在表示されている先頭文字に対応するキーコードはKCode[RND[cnt]]と表されます。 入力されたキーと問題文のキーコードを比較するif文の中でKCode[RND[cnt]]が出てきた理由がお分かり頂けたでしょうか。
他に文字の切り取りや乱数の作成、時間の計算等について復習なさりたい方は、以下のリンクを参照なさってください。
グローバル変数, Math.floor(), Math.random(), substring(), innerHTML, new Date()
少し改良したタイピングゲーム
上記のタイピングゲームでは、文字がザ~と流れて目がチカチカします。 それで少しだけ改良したものを作ってみました。プレイして比べてみてください。
このスクリプトでは、文字を切り取らずに色を薄く(灰色)していきます。 ただ上のままのスクリプトで色変えを行うと、 折り返し部分で文字が次の行に行ったり戻ったりして見にくくなりました。 それでテーブルを使って文字を表示するようにしています。
テーブルの各セルにID名を付けて、そのセルの文字色を灰色にするようにしています。 詳しく解説はしませんが、関心がおありの方は是非ソースを覗いて研究なさってください。