こんばんは!
JavaScriptでタイピングゲームを作ってみたので、コードを共有したいと思います
今回のプログラムはこちらで動かすことができます
ソースコード
ソースコードになります
工夫した点としては
・audioタグを使用し、タイピングミスをした時にはエラー音が鳴る
・どの文字を打つべきか分かるように、正解している部分を赤色にする
・いきなりゲームが始まらないように、カウントダウンをしている
です
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | <!DOCTYPE html> <html> <head> <title>タイピングゲーム</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="typing.css" /> <audio src ="_sound_anime_mp3_incorrect1.mp3" id="missaudio">現環境では音が鳴りません</audio> <audio src ="_sound_battle_mp3_handgun-out-bullets1.mp3" id="correctaudio"></audio> <script> var wordlist = ["aaiebakouiu","isogabamaware","uogokoroarebamizugokoro","ennositanotikaramoti","oninomenimonamida","kaiinunitewokamareru","kyuusiniissyouwoeru","kutihawazawainomoto","geijutuhanagakujinseihamijikasi","koukaisakinitatazu","sarumokikaraotiru","siranugahotoke","suimoamaimokamiwaketa","zenhaisoge","daihasyouwokaneru","tirimotumorebayamatonaru","turuhasennenkamehamannen","tenhanibutuwoataezu","tokihakanenari","nagaimononihamakarero","nidoarukotohasandoaru","nukanikugi","nekonotemokaritai","norenniudeosi","hayaokihasanmonnotoku","hinonaitokoronikemurihatatanu","hukusuibonnikaerazu","benkeinonakidokoro","hotokenokaomosando","mayugewoyomareru","mikaradetasabi","musumehitorinimukohatinin","menihame,hanihaha","motonosayaniosamaru","yakeisinimizu","yudantaiteki","yowarimenitatarime","rakuhakunotane,kuharakunotane","ryouyakuhakutininigasi","ruihatomowoyobu","reiniyottereinogotosi","rongoyominorongosirazu","waraukadonihahukukitaru"]; var wordlistJapanese = ["ああ言えばこう言う","急がば回れ","魚心あれば水心","縁の下の力持ち","鬼の目にも涙","飼い犬に手を噛まれる","九死に一生を得る","口は禍の元","芸術は長く人生は短し","後悔先に立たず","猿も木から落ちる","知らぬが仏","酸いも甘いも噛み分けた","善は急げ","大は小を兼ねる","塵も積もれば山となる","鶴は千年亀は万年","天は二物を与えず","時は金なり","長い物には巻かれろ","二度あることは三度ある","糠に釘","猫の手も借りたい","暖簾に腕押し","早起きは三文の徳","火のないところに煙は立たぬ","覆水盆に反らず","弁慶の泣き所","仏の顔も三度","眉毛を読まれる","身から出た錆","娘一人に婿八人","目には目、歯には歯","元の鞘に納まる","焼け石に水","油断大敵","弱り目に祟り目","楽は苦の種、苦は楽の種","良薬は口に苦し","類は友を呼ぶ","例によって例の如し","論語読みの論語知らず","笑う門には福来たる"]; var time_limit = 90; var readytime = 3; var score; var correct; var mistake; var char_num = 0; var word_char; var random; function ready(){ readytime = 3; scoredis.innerHTML=""; start_button.style.visibility ="hidden"; var readytimer = setInterval(function(){ count.innerHTML=readytime; readytime--; if(readytime < 0){ clearInterval(readytimer); gameStart(); } },1000); } function gameStart(){ score = 0.0; mistake = 0; correct = 0; wordDisplay(); var time_remaining = time_limit; var gametimer = setInterval(function(){ count.innerHTML="残り時間:"+time_remaining; time_remaining--; if(time_remaining <= 0){ clearInterval(gametimer); finish(); } },1000); } function wordDisplay(){ random = Math.floor( Math.random() * wordlist.length ); word.innerHTML=wordlist[random]; japanese.innerHTML=wordlistJapanese[random]; charInsort(); } function charInsort(){ word_char = wordlist[random].charAt(char_num); } function finish(){ score = Math.floor(Math.pow(correct,2) * Math.pow((correct/(correct+mistake)),5)); scoredis.innerHTML="スコア:"+score+"点"+"<hr>正タイプ数:"+correct+"<br>ミスタイプ数:"+mistake+"<br>正答率"+(correct/(correct+mistake)*100).toFixed(1)+"%"; count.innerHTML=""; word.innerHTML=""; japanese.innerHTML=""; start_button.style.visibility ="visible"; word_char=0; random = 0; char_num = 0; } document.onkeydown = function(e) { if(e.keyCode == 189){ keyStr = "-"; }else if(e.keyCode == 188){ keyStr = "," }else{ var keyStr = String.fromCharCode(e.keyCode); keyStr = keyStr.toLowerCase(); } if(keyStr == word_char){ document.getElementById('missaudio').pause(); document.getElementById('missaudio').currentTime = 0; document.getElementById('correctaudio').pause(); document.getElementById('correctaudio').currentTime = 0; document.getElementById('correctaudio').play(); word.innerHTML="<span style='color: red;'>"+wordlist[random].substr(0,char_num+1)+"</span>"+wordlist[random].substr(char_num+1,wordlist[random].length); char_num++; correct++; charInsort(); }else{ document.getElementById('missaudio').pause(); document.getElementById('missaudio').currentTime = 0; document.getElementById('correctaudio').pause(); document.getElementById('correctaudio').currentTime = 0; mistake++; document.getElementById('missaudio').play(); } if(char_num == wordlist[random].length){ char_num=0; wordDisplay(); } }; </script> </head> <body> <div class="wrap"> <input type="button" id="start_button" value="start" onclick="ready()" style="text-align: center"> <div id="count"></div> <h1><div id="japanese"></div></h1> <h2><div id="word"></div></h2> <div id="scoredis"></div> </div> </body> </html> |
ボタンを中央に配置するためにcssファイルも作成しました
1 2 3 | .wrap{ text-align:center; } |
追記:改行について
「アルファベットの文字列を改行して表示することはできないか」という質問をいただきました。
brタグを挿入すれば、アルファベットの文字列を改行して表示することができますが、タイピングの際に不具合が生じます。
それを解決する単純な方法としては以下のようなものになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | <!DOCTYPE html> <html> <head> <title>タイピングゲーム</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="typing.css" /> <audio src ="_sound_anime_mp3_incorrect1.mp3" id="missaudio">現環境では音が鳴りません</audio> <audio src ="_sound_battle_mp3_handgun-out-bullets1.mp3" id="correctaudio"></audio> <script> var wordlist = ["aaieba<br>kouiu","waraukadoniha<br>hukukitaru"]; var wordlistJapanese = ["ああ言えばこう言う","笑う門には福来たる"]; var time_limit = 90; var readytime = 3; var score; var correct; var mistake; var char_num = 0; var word_char; var random; var replacewordlist = []; function ready(){ readytime = 3; scoredis.innerHTML=""; start_button.style.visibility ="hidden"; var readytimer = setInterval(function(){ count.innerHTML=readytime; readytime--; if(readytime < 0){ clearInterval(readytimer); gameStart(); } },1000); } function gameStart(){ score = 0.0; mistake = 0; correct = 0; wordDisplay(); var time_remaining = time_limit; var gametimer = setInterval(function(){ count.innerHTML="残り時間:"+time_remaining; time_remaining--; if(time_remaining <= 0){ clearInterval(gametimer); finish(); } },1000); } function wordDisplay(){ random = Math.floor( Math.random() * wordlist.length ); replacewordlist[random] = wordlist[random].replace("<br>",""); word.innerHTML = wordlist[random]; japanese.innerHTML = wordlistJapanese[random]; charInsort(); } function charInsort(){ word_char = replacewordlist[random].charAt(char_num); } function finish(){ score = Math.floor(Math.pow(correct,2) * Math.pow((correct/(correct+mistake)),5)); scoredis.innerHTML="スコア:"+score+"点"+"<hr>正タイプ数:"+correct+"<br>ミスタイプ数:"+mistake+"<br>正答率"+(correct/(correct+mistake)*100).toFixed(1)+"%"; count.innerHTML=""; word.innerHTML=""; japanese.innerHTML=""; start_button.style.visibility ="visible"; word_char=0; random = 0; char_num = 0; } document.onkeydown = function(e) { if(e.keyCode == 189){ keyStr = "-"; }else if(e.keyCode == 188){ keyStr = "," }else{ var keyStr = String.fromCharCode(e.keyCode); keyStr = keyStr.toLowerCase(); } if(keyStr == word_char){ document.getElementById('missaudio').pause(); document.getElementById('missaudio').currentTime = 0; document.getElementById('correctaudio').pause(); document.getElementById('correctaudio').currentTime = 0; document.getElementById('correctaudio').play(); //word.innerHTML="<span style='color: red;'>"+wordlist[random].substr(0,char_num+1)+"</span>"+wordlist[random].substr(char_num+1,wordlist[random].length); char_num++; correct++; charInsort(); }else{ document.getElementById('missaudio').pause(); document.getElementById('missaudio').currentTime = 0; document.getElementById('correctaudio').pause(); document.getElementById('correctaudio').currentTime = 0; mistake++; document.getElementById('missaudio').play(); } if(char_num == replacewordlist[random].length){ char_num=0; wordDisplay(); } }; </script> </head> <body> <div class="wrap"> <input type="button" id="start_button" value="start" onclick="ready()" style="text-align: center"> <div id="count"></div> <h1><div id="japanese"></div></h1> <h2><div id="word"></div></h2> <div id="scoredis"></div> </div> </body> </html> |
もとのプログラムからの変更点としては
brタグをwordlistの文字列に挿入して、改行されたものを表示します。
そしてreplace()メソッドを使って、brタグを除いた文章を作成し、その文章に対して入力された文字の正誤判定を行っています。
だたし、このプログラムだと最初のものと違って、入力された文字の色を変更することができません。
入力された文字の色を変更するために、さらに少し改良したものが以下のコードになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | <!DOCTYPE html> <html> <head> <title>タイピングゲーム</title> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="typing.css" /> <audio src ="_sound_anime_mp3_incorrect1.mp3" id="missaudio">現環境では音が鳴りません</audio> <audio src ="_sound_battle_mp3_handgun-out-bullets1.mp3" id="correctaudio"></audio> <script> var wordlist = ["aaieba<br>kouiu","waraukadoniha<br>hukukitaru","umanomimininenbutu"]; var wordlistJapanese = ["ああ言えばこう言う","笑う門には福来たる","馬の耳に念仏"]; var time_limit = 90; var readytime = 3; var score; var correct; var mistake; var char_num = 0; var word_char; var random; var newline; var replacewordlist = []; function ready(){ readytime = 3; scoredis.innerHTML=""; start_button.style.visibility ="hidden"; var readytimer = setInterval(function(){ count.innerHTML=readytime; readytime--; if(readytime < 0){ clearInterval(readytimer); gameStart(); } },1000); } function gameStart(){ score = 0.0; mistake = 0; correct = 0; wordDisplay(); var time_remaining = time_limit; var gametimer = setInterval(function(){ count.innerHTML="残り時間:"+time_remaining; time_remaining--; if(time_remaining <= 0){ clearInterval(gametimer); finish(); } },1000); } function wordDisplay(){ random = Math.floor( Math.random() * wordlist.length ); replacewordlist[random] = wordlist[random].replace("<br>/g",""); newline = wordlist[random].indexOf("<"); word.innerHTML = wordlist[random]; japanese.innerHTML = wordlistJapanese[random]; charInsort(); } function charInsort(){ word_char = replacewordlist[random].charAt(char_num); } function finish(){ score = Math.floor(Math.pow(correct,2) * Math.pow((correct/(correct+mistake)),5)); scoredis.innerHTML="スコア:"+score+"点"+"<hr>正タイプ数:"+correct+"<br>ミスタイプ数:"+mistake+"<br>正答率"+(correct/(correct+mistake)*100).toFixed(1)+"%"; count.innerHTML=""; word.innerHTML=""; japanese.innerHTML=""; start_button.style.visibility ="visible"; word_char=0; random = 0; char_num = 0; } document.onkeydown = function(e) { if(e.keyCode == 189){ keyStr = "-"; }else if(e.keyCode == 188){ keyStr = "," }else{ var keyStr = String.fromCharCode(e.keyCode); keyStr = keyStr.toLowerCase(); } if(keyStr == word_char){ document.getElementById('missaudio').pause(); document.getElementById('missaudio').currentTime = 0; document.getElementById('correctaudio').pause(); document.getElementById('correctaudio').currentTime = 0; document.getElementById('correctaudio').play(); word.innerHTML="<span style='color: red;'>"+wordlist[random].substr(0,char_num+1)+"</span>"+wordlist[random].substr(char_num+1,wordlist[random].length); char_num++; if(newline == char_num){ char_num = char_num + 4; } correct++; charInsort(); }else{ document.getElementById('missaudio').pause(); document.getElementById('missaudio').currentTime = 0; document.getElementById('correctaudio').pause(); document.getElementById('correctaudio').currentTime = 0; mistake++; document.getElementById('missaudio').play(); } if(char_num == wordlist[random].length){ char_num=0; wordDisplay(); } }; </script> </head> <body> <div class="wrap"> <input type="button" id="start_button" value="start" onclick="ready()" style="text-align: center"> <div id="count"></div> <h1><div id="japanese"></div></h1> <h2><div id="word"></div></h2> <div id="scoredis"></div> </div> </body> </html> |
brタグをreplaceしていないwordlistでは、"<br>"が4文字として加算されてしまうため、入力文字の色をうまく変えられないのだと思います。
ですので、"<br>"の最初の”<"の文字が文字列の中で何文字目にあるかをindexOf()メソッドで取得し、"<"が来る直前にchar_numを+4することで対策しています。
ただ、このコードはbrタグが2つ以上の場合に対応していないので注意して下さい。
効果音
今回のプログラムで使用した効果音は「効果音ラボ」からダウンロードしました