jqueryでタイピングゲームを作成してみた
jqueryを覚えたのでタイピングゲームを作成してみた。
デザインはタイプウェルを参考にさせていただいています。(
http://www.twfan.com/
)
とりあえず動く程度のレベルなので、デザインとか機能とかはもっと改善したいところ。
動作確認したのはChoromeのみ
実装した機能
・タイマー
・ミス数表示
・入力したものは赤くなる
・入力文字表示枠
今後実装したい機能
・ミス時に通知する機能(音とか文字色変更とか)
・リザルト画面(単語ごとのタイムとかミスした箇所とか)
・再チャレンジ用のリセット機能
・あいまい入力対応("し"の場合 si or shi のどちらも可能にする。:これは難しそう)
・対象の単語を外部ファイルから読み込むようにする。
所感
グローバル変数使い過ぎな気もするのでちゃんとリファクタリングしたいなぁ
区切り文字を","にしたのはかなりセンスないorz
javascriptは初心者なので、書き方変だよとかあればコメントください。
使って遊びたい場合は、candidateWordとcreateWordsのforの数をいじれば、自分の好きなように設定できます。
typingGame.html
<!doctype html> <html> <head> <script type="text/javascript" src=".\jquery.js"></script> <script type="text/javascript" src=".\typingGame.js"></script> </head> <body style="width:100%; height:100%;"> <span class="start"> </span> <input class="ready" type="button" onclick="start();" value="READY"> <span>Time</span> <span class="time" ></span> <span >miss:</span> <span class="miss" >0</span> <!-- 日本語欄 --> <div class="textJp"> <span class="endInputJp" style="color:red"></span><span class="yetInputJp"></span></div> <!-- 英語(ローマ字)欄 --> <div class="textEn"> <span class="endInputEn" style="color:red"></span><span class="yetInputEn"></span></div> <!-- 入力欄 --> <div class="inputareaJp" style="font-size:20px;"><span class="endInputareaJp"> </span><span class="nowInputareaJp" style="border:solid 1px;"> </span><span class="yetInputareaJp"></span></div> <!-- ログ欄 --> <div class="log"> 入力キー:</div> </body> </html>
typingGame.js
var isStart = false; // 準備後 var canKeyUp = false; // 入力可能状態 var isEnd = false; // 完了したかどうか var Word = function(jp,en){ // 単語のコンストラクタ this.jp = jp; this.en = en; // ローマ字 日本語1文字につき[,]で区切る(最後も) } var words =[]; // タイピングする単語の配列 var candidateWord = [new Word("テスト","te,su,to,"), new Word("単語","tann,go,"), new Word("タイピング","ta,i,pi,nn,gu,")]; var dispJp; // 表示用の日本語 var dispEn; // 表示用の英語 var inputEn; // 入力用の英語 $(function(){ var miss = 0; $("html").keyup(function(){ var key = event.key; if(!isStart){ if(key == " "){ // スペースで開始する(クリックするとキーボードから手が離れるし) $(".ready").click(); } }else{ // カウントダウンが終わるまでは何もしない if(canKeyUp){ // 開始後 // ログ出力 $(".log").append(key); // 正解のローマ字 var okChar = dispEn.slice(0,1); if(key == okChar){ // 正解の場合 dispEn = dispEn.slice(1); // 先頭文字削除 inputEn = inputEn.slice(1); $(".yetInputEn").text(dispEn); $(".endInputEn").append(okChar); // 日本語を1字入力完了した場合 if(inputEn.slice(0,1) == ","){ inputEn = inputEn.slice(1); // ,を削除 $(".endInputJp").append(dispJp.slice(0,1)); // 先頭文字設定 $(".endInputareaJp").text($(".endInputareaJp").text().slice(1) + dispJp.slice(0,1)); dispJp = dispJp.slice(1); // 先頭文字削除 $(".nowInputareaJp").text(dispJp.slice(0,1)); $(".yetInputareaJp").text(dispJp.slice(1,6)); $(".yetInputJp").text(dispJp); } // 完了時 if(dispEn.length == 0){ isEnd = true; alert("完了"); } }else{ // 不正解の場合 miss++; $(".miss").text(miss); } } } }); }); /** * 開始処理を行う */ function start(){ if(isStart){ // 開始後はなにもしない return; } // readyボタンのオンクリック処理をなくす $(".ready").prop("disabled", true); isStart=true; var startCountdown = 3; // スタートするまでの秒数 var countSpace = " "; // 先にtyping対象を表示しちゃう createWords(); dispJp = getDispJp(); inputEn = getDispEn(); dispEn = inputEn.replace(/,/g,""); // ,を消す $(".yetInputJp").text(dispJp); $(".yetInputEn").text(dispEn); $(".start").text(countSpace + startCountdown); $(".nowInputareaJp").text(dispJp.slice(0,1)); $(".yetInputareaJp").text(dispJp.slice(1,6));// 表示枠は5文字とする setInterval(function(){ if(!canKeyUp){ startCountdown--; if(startCountdown > 0){ $(".start").text(countSpace + startCountdown); }else{ $(".start").text(" start"); canKeyUp = true; // startしたので入力可能 // タイマーを設定 var startTime = new Date(); $(".time").text(0); setInterval(function(){ if(!isEnd){ // 少数第一位まで表示 var timems = new Date - startTime; $(".time").text(Math.floor((timems/1000)) + "." + Math.floor((timems/100)%10 )); } },100); } } },1000); } /** * タイピング対象の単語を作成する */ function createWords(){ // テストなので5単語を出力する for(i = 0; i < 5; i++){ // 入力候補からランダムで決める words.push(candidateWord[Math.floor(Math.random() * candidateWord.length)]); } } /** * タイピング対象の日本語をスペース区切りですべて取得する */ function getDispJp(){ var dispStr =""; $.each(words, function(index,value){ dispStr += value.jp + " "; }); // 最後のスペースを削除 dispStr = dispStr.slice(0, -1); return dispStr; } /** * タイピング対象の英語をスペース区切りですべて取得する */ function getDispEn(){ var dispStr =""; $.each(words, function(index,value){ dispStr += value.en + " ,"; }); dispStr = dispStr.slice(0, -1); return dispStr; }
javascriptを書く位置と取得できるDOM
javascriptでonload時にイベントリスナーの設定しようとして、body部の要素が取得できず、
つまづいたため、javascriptの書く位置と取得できる要素についてまとめてみた。
結論:onload時は自分より下の要素は取れないよ!
loadtest.html
<!DOCTYPE HTML> <HTML> <HEAD> <SCRIPT type="text/javascript"> (function(){ alert("Head_即時関数:body_" + document.body + "_本文:" + document.getElementById("text")); }()); window.onload = function(){ alert("Head_onload:body_" + document.body + "_本文:" + document.getElementById("text")); }(); function disp1(){ alert("Head_function :body_" + document.body + "_本文:" + document.getElementById("text")); } </SCRIPT> </HEAD> <BODY> <SCRIPT type="text/javascript"> (function(){ alert("Body_start_即時関数:body_" + document.body + "_本文:" + document.getElementById("text")); }()); window.onload = function(){ alert("Body_start__onload:body_" + document.body + "_本文:" + document.getElementById("text")); }(); function disp2(){ alert("Body_start_function :body_" + document.body + "_本文:" + document.getElementById("text")); } </SCRIPT> <!-- 取得対象の要素 --> <div id="text">文章</div> <input type="button" onclick="disp1()" value="Head"> <input type="button" onclick="disp2()" value="body_start"> <input type="button" onclick="disp3()" value="body_end"> <SCRIPT type="text/javascript"> (function(){ alert("Body_end_即時関数:body_" + document.body + "_本文:" + document.getElementById("text")); }()); window.onload = function(){ alert("Body_end__onload:body_" + document.body + "_本文:" + document.getElementById("text")); }(); function disp3(){ alert("Body_end_function :body_" + document.body + "_本文:" + document.getElementById("text")); } </SCRIPT> </BODY> </HTML>
結果
即時間数 | onload | function | |
---|---|---|---|
Head | × | × | 〇 |
Body_start | △ | △ | 〇 |
Body_end | 〇 | 〇 | 〇 |
〇…両方取得できる。 △…bodyのみ取得できる。 ×…取得できない。
VBScriptでDocumentとdocumentは何か違うのか?
仕事の都合上vbscriptをしているが、そこで謎の発見があった。
IE9 or IE10でDocumentだとallがないが、documentだと使える。
(IE8以前は両方使える)
不思議なことに先にdocumentを使用するとDocumentもallが使えるようになり、
先にDocumentを使用するとdocumentでallが使えなくなる。
以下で再現可能
test.html
<!DOCTYPE HTML> <HTML> <HEAD> <meta http-equiv="x-ua-compatible" content="IE=9"> <SCRIPT type="text/vbscript" src=".\uppercase.vbs"></SCRIPT> <SCRIPT type="text/vbscript" src=".\lowercase.vbs"></SCRIPT> </HEAD> <BODY> <input id="id" type="text"> <input type="button" onclick="vbscript:uppercase()" Value="Document"> <input type="button" onclick="vbscript:lowercase()" Value="document"> </BODY> </HTML>
uppercase.vbs
Function uppercase() Msgbox(Document.all("id").value) END Function
lowercase.vbs
Function lowercase() Msgbox(document.all("id").value) END Function
Documentボタンをクリックしても何も表示されないし、その後にdocumentボタンをクリックしても何も表示されない。
が、documentボタンを先にクリックするとテキストボックスに入力された値が表示され、その後にDocumentボタンをクリックしても表示される
Documentとdocumentで最初にロードされる型が違って、その後は大文字小文字の区別なく同じ型が呼び出されるってことなのかな?