0
0

More than 1 year has passed since last update.

1ファイルでタイピングゲームを作る

Last updated at Posted at 2021-05-28
1つのhtmlファイルで、タイピングゲームを作成します。
  • タイピングする文字は、preタグに入れておきます。
  • javascriptでこれから打つ文字、打ち終わった文字をそれぞれのpre内のspanタグに入れます。
  • これから打つ文字、打ち終わった文字は、CSSで見た目を変えます。
  • 残り時間は、setIntervalで減らしていきます。
  • ゲーム開始前に、初期の残り時間を増やしたり、減らしたりできます。

ちょっと制限としては次のような感じです。

  • プログラムのタイプ練習用としているので、字下げ部分は、タイプしなくても先に進むようになっています。
  • その字下げは、ゲーム内ではスペース2つ以上が連続するところ、と判断しているので、字下げ以外でスペース2つ以上を作ると、タイプせずに飛ばされてしまいます。

また別記事の1つのjsファイルで効果音を鳴らすを利用すると、タイプ音を付けることもできます。

ソースコードです。

typing.js.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <style>
        /* innerを画面中央に配置するために、外側の要素をposition:relativeにする。*/
        .outer {
            position: relative;
        }
        /* leftで要素の左側を画面中央に、transformで要素の半分だけ左側に移動して、中央配置にする。*/
        .inner {
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
        }
        /* ゲーム開始前の「スペースキーで開始」を表示する要素 */
        #overlay {
            position:absolute;
            left: 50%;
            top: 50%;
            transform: translateX(-50%) ;
            background-color: blanchedalmond;
            font-size:small;
            padding: 20px;
        }
        /* 要素の消去 */
        .none {
            display: none;
        }
        /* ゲーム実行中に表示される説明部分の要素 */
        #message {
            position: absolute;
            font-size: large;
        }
        /* タイピングする文字の全体(これから打つもの、打ったもの) */
        #panel {
            font-size:xx-large;
        }
        /* 打ち終わった文字 */
        #done {
            background-color:grey;
        }
        /* 記録などを表示するヘッダー部分 */
        #header {
            font-size:medium;
            position:absolute;
            transform: translateX(-10%);
            width: 600px;
        }
        /* 時間表示部分 */
        #time {
            font-size: large;
        }
    </style>
</head>
<body class="outer">
    <div id="panel" class="inner">
        <div id="header">
			残り時間: <span id="time">0</span>
			自分の記録: <span id="hist"></span>
		</div>

        <!-- #textにタイピングする文字を入れる。 #done, #typeは、それぞれ打ち終わったもの、これから打つものが入る。 -->
        <pre id="text"><span id="done"></span><span id="type">int i=0;
scanf("%d",&i);
printf("i=%d\n",i);
int values[5] = {4,6,1,4,2};
int cnt=0;
while(cnt<5){
    if(values[cnt]>i){
        printf("v=%d\n",values[cnt]);
    }
    cnt+=1;
}</span></pre>

        <div id="overlay">スペースキーで開始</div>
        <div id="message"></div>
    </div>

    <script type="text/javascript">
        // 最初にタイピングする文字を取得しておく。
        const text = $("#text").text();
        // タイピングする文字のどこまでを打ったかを記録する変数
        let text_i = 0;
        // 残り時間を管理する lm の値を変更すると、初期の残り時間を変更できる。
        let tm = {
            id:undefined, // setIntervalのid
            st:undefined, // タイピングの開始時間
            lm:150*1000, // タイピングのリミット時間(ミリ秒)
            tm:()=>(new Date()).getTime()-tm.st, // 経過時間
            rs:()=>tm.lm - tm.tm(), // 残り時間
            fm:(t)=>(Number(t)/1000).toFixed(1),
            clear:()=>{clearInterval(tm.id);},
        };
        // タイピングの記録を、履歴として記録する。
        let data = [];
        // ゲーム開始前に、+文字、-文字を打つと、初期の残り時間を増やす/減らすことができる。
		const tm_ctrl = {"+":10*1000,"-":-10*1000};

        // 時間を表示
        $("#time").text(tm.fm(tm.lm));
        // 現在のタイピングしている文字(打ち終わったもの、これから打つもの)を表示するラムダ関数
        const disp = ()=>{
            $("#done").text(text.slice(0,text_i));
            $("#type").text(text.slice(text_i));
        }
        // キーが押されたときの処理
        $(window).on("keydown",(e)=>{
            // #overlayの要素がある場合は、ゲーム開始前と判断する。
            if($("#overlay").hasClass("none")===false){
                // ゲーム開始のスペース以外が押された場合は、初期の残り時間を増減するキー以外は無視する。
                if(e.key !== " "){
                    tm.lm += e.key in tm_ctrl ? tm_ctrl[e.key] : 0;
                    $("#time").text(tm.fm(tm.lm));
                    return;
                }
                // #overlayの要素を消去して、時間計測を開始する。
                $("#overlay").toggleClass("none");
                tm.st = (new Date()).getTime();
                tm.id = setInterval(()=>{
                    $("#time").text(tm.fm(tm.rs()));
                },100);
            }
            // 入力されたキーを、タイピングする文字と一致しているか比較するために、Enterキーの変換等をする。
            const c = {
                key:e.key,
                code:Number(e.key.replace("Enter","10")),
            };
            // 入力がタイピングするキーと一致している場合、
            if(text[text_i]===c.key || text[text_i].charCodeAt()===c.code){
                // これから打つタイピング文字が、2つ以上連続するスペースである場合は、その先までこれから打つ文字を移動させる。
                text_i += 1;
				let a = 0;
				while(text[text_i]===" " && text[text_i+1]===" "){
					text_i += 1;
					a = 1;
				}
				text_i += a;
                // 現在のタイピング文字を表示する。
                disp();
            }
            // ゲーム中に表示する説明文を定義する。
            const msgs = {
                "10":"Enterを押してください。",
                "32":"スペースキーを押してください。",
            };
            // これから打つ文字によって、説明文を画面に表示する。
            const n = text.charCodeAt(text_i);
            $("#message").text(n in msgs ? msgs[n] : "");

            // すべての文字をタイプし終わったとき、
            if(text.length===text_i){
                // ゲームをリセットして、時間を履歴に追加する。
                text_i = 0;
                disp();
                $("#overlay").toggleClass("none");
                data.push(tm.rs());
                tm.clear();
                $("#hist").text(data.map(d=>tm.fm(d)).join(","));
            }
        });
    </script>
</body>
</html>

タイプ音を付ける。

1つのjsファイルで効果音を鳴らすを利用して、正解をタイプしたときにタイプ音を鳴らします。

sound.jsファイルを読み込んでおいて、
image.png

javascriptの最初の方でsound.init()で初期化して、
image.png

正解をタイプしたときに、sound.play()でタイプ音を鳴らします。
image.png

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0