解説コードを読んでみよう
このサンプルでわかること
keydownイベントで、押されたキーを調べる方法- 「お題の何文字目まで打てたか」を変数で管理する考え方
- SVG で描いた図形の色を JavaScript から変える方法
- ブラウザの音声合成(
SpeechSynthesisUtterance)でお題を読み上げる方法
使っているファイル
- english.html英語版のゲーム本体(HTML・SVG・JavaScript)
- alphabet.js英語キーボードの「キーの番号 ⇔ 文字」の対応表
- jp-kana.html / ja-kana.js日本語かな入力版と、かな配列の対応表
- korean.html / hangul.jsハングル版と、ハングル配列の対応表
- tw.html / tw-bopomofo.js注音(繁体字)版と、注音配列の対応表
- index.phpこのページ。タブで言語を切り替えて iframe に表示
4つの言語版は、プログラムの部分がほぼ同じです。違うのは「お題」と「キーの対応表(○○.js)」だけなので、ここでは英語版(english.html)で説明します。
1. 画面の部品を用意する
お題の意味(#m)、お題(#w)、補足(#c)、点数とタイマーを表示する場所を HTML で用意します。中身は空にしておき、JavaScript から書き込みます。
<body>
<p id="m"></p>
<p id="w"></p>
<p id="c"></p>
<p class="info">
タイプ数: <span id="score">0</span>,
ミスタッチ数: <span id="miss">0</span>,
経過時間: <span id="timer">00:00.000</span>
</p>
2. キーと文字の対応表を作る
キーボードのキーには、それぞれ番号(キーコード)があります。たとえば A は 65 です。どのキーを押すとどの文字になるか、Shift が必要かを表にしたのが alphabet.js です。
var list =
[
{ key: '49', value: '1', shift: false},
{ key: '50', value: '2', shift: false},
{ key: '51', value: '3', shift: false},
{ key: '52', value: '4', shift: false},
日本語かな版では、同じキー番号に「ぬ」「ふ」などのかな文字を対応させています。表を差し替えるだけで別の言語のゲームになる、というのがこの作りのよいところです。
3. キーボードの図を SVG で描く
キーボードの絵は、SVG の <rect>(四角)と <text>(文字)を並べて描いています。それぞれの四角には id="key_65" のようにキー番号入りの id をつけておきます。こうすると、あとで「65番のキーを光らせる」が簡単にできます。
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 670 250" style="width:100%;max-width:670px;height:auto">
<rect id="key_49" x="0" y="0" width="48" height="48" rx="5" ry="5" fill="none" stroke="#000000" />
<rect id="key_50" x="50" y="0" width="48" height="48" rx="5" ry="5" fill="none" stroke="#000000" />
<rect id="key_51" x="100" y="0" width="48" height="48" rx="5" ry="5" fill="none" stroke="#000000" />
<rect id="key_52" x="150" y="0" width="48" height="48" rx="5" ry="5" fill="none" stroke="#000000" />
<rect id="key_53" x="200" y="0" width="48" height="48" rx="5" ry="5" fill="none" stroke="#000000" />
4. お題を用意する
お題は配列 words にまとめます。1つのお題は m(意味)・w(打つ文字)・c(補足)の3つを持つオブジェクトです。
var words =
[
{m:'こんにちは、世界', w:'Hello World', c:''},
{m:'さあ、始めよう', w:'It\'s show time.', c:''},
{m:'おはよう!', w:'Good morning!', c:''},
{m:'上の段', w:'QWERTYUIOP', c:'キーボードの上の段のキー'},
{m:'真ん中の段', w:'ASDFGHJKL', c:'ホームポジションの段'}
]
5. 次のお題を表示して、読み上げる
setTarget() は、次のお題を画面に表示する関数です。最初に SpeechSynthesisUtterance でお題を読み上げ、次に押すべきキーを緑色(#98FB98)に塗ります。
//*NextPhrase
function setTarget(next) {
var synthes = new SpeechSynthesisUtterance(words[next].w);
synthes.lang = "en-US";
speechSynthesis.speak( synthes );
currentWord = words[next].w;
w.innerHTML = currentWord;
m.innerHTML = words[next].m;
c.innerHTML = words[next].c;
currentLocation = 0;
for (var x = 0; x < listLength; x++) { //予知色
if(list[x].value == currentWord[currentLocation]){
document.getElementById('key_' + list[x].key).setAttribute('fill','#98FB98');
if(list[x].shift == true){
shiftColor('#9ACD32');
}else{
shiftColor('none');
}
}
}
}
6. 押されたキーが正しいか判定する
ゲームの中心は keydown(キーが押されたとき)のイベントです。押されたキー番号 e.keyCode と Shift の有無から、対応表で文字を調べ、お題の今の位置の文字 currentWord[currentLocation] と同じかどうかを比べます。
//*キー判定
window.addEventListener('keydown', function(e) {
if (!isStarted) {
return;
}
for (var j = 0; j < listLength; j++) {
if(list[j].value == currentWord[currentLocation]){
currentShift = list[j].shift;
}
}
wordsShift=false;
shift = e.shiftKey;
for (var j = 0; j < listLength; j++) {
if(list[j].key == e.keyCode && list[j].shift == shift){
listValue = list[j].value;
wordsShift=list[j].shift;
}
}
if (listValue == currentWord[currentLocation]){
currentLocation++;
keyLocation++
- 正解なら:
currentLocationを1つ進め、打ち終わった文字を*に置き換えて表示します。 - まちがいなら:
missを1つ増やします。ただし、Shift キーそのものを押しただけのときはミスにしません。
var placeholder = '';
for (var i = 0; i < currentLocation; i++) {
placeholder += '*';
}
w.innerHTML = placeholder + currentWord.substring(currentLocation);
7. 最後のお題まで打ったら結果を出す
お題を最後まで打ち終わり、さらにそれが最後のお題(num-1 == next)なら、タイマーを止めて正確性を表示します。
scoreLabel.innerHTML = score;
if (currentLocation === currentWord.length) {
if (num-1 == next){
clearTimeout(timerId);
timer = document.getElementById('timer');
console.dir(timer.innerHTML); //データベースへ登録値
next = 0;
m.innerHTML = '';
c.innerHTML = '';
w.innerHTML = '正確性: ' + floatFormat(score / (score + miss) * 100, 1) + '%<br>Press any key to start<br>もう一度チャレンジする';
score = 0;
miss = 0;
keyLocation = 0;
shiftColor('none');
setTimeout(function(){isStarted = false;}, 1000);
}else{
next = next + 1;
setTarget(next);
}
正確性は「正しく打った数 ÷(正しく打った数+ミスの数)× 100」で計算しています。書き直す前は計算式がまちがっていて、ほぼ常に 100% 近くになっていたので修正しました。あわせて、経過時間のミリ秒が2桁しか表示されない不具合も直しています。
8. タブで言語を切り替える(index.php)
このページでは、ゲーム本体を <iframe> で埋め込んでいます。タブのボタンに data-src でファイル名を持たせておき、押されたら iframe の src を書き換えるだけで、別の言語版に切り替わります。
<div class="typing-tabs" role="tablist">
<button type="button" class="is-active" data-src="english.html">英語</button>
<button type="button" data-src="jp-kana.html">日本語かな</button>
<button type="button" data-src="korean.html">ハングル</button>
<button type="button" data-src="tw.html">注音(繁体字)</button>
</div>
<script>
// タブを押したら iframe の中身(ゲームの言語)を切り替える
$(function(){
$('.typing-tabs button').on('click', function(){
$('.typing-tabs button').removeClass('is-active');
$(this).addClass('is-active');
$('.demo-frame').attr('src', $(this).data('src'));
});
});
</script>
e.keyCode は古い書き方で、今は e.key(押された文字)や e.code(キーの位置)を使うのがおすすめです。ただ、かな入力やハングルのように「同じキーで別の文字」になるゲームでは、キーの位置で判定する考え方そのものは今でも役に立ちます。
words のお題を自分の好きな英単語に変えてみましょう。対応表にない文字(たとえば数字の後ろの記号)を入れると打てなくなるので、そのときは alphabet.js を確認してみてください。