javascript part4 -タイピングゲーム

タイピングゲーム

今回はこちらのサイトを参照させていただいて、タイピングゲームを作っていこうと思う。初心者なので、真似して実際に作ってみないとわからない。
コードはこちらのサイトに書かれてあるので、そちらを参照していただければ。
さて、やっていこう。

https://php-archive.net/javascript/js-typing/(最終閲覧2020/06/01)

Google Hosted Libraries

さて、まず気になるのが以下のコード。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>

ライブラリのjQueryを使うので、それを呼び出している。実際、なんのこっちゃという話。

The Google Hosted Libraries is a stable, reliable, high-speed, globally available content distribution network for the most popular, open-source JavaScript libraries.(オープンソースのJavaScriptライブラリ向けの、グローバルで利用可能な安定した信頼できる高速コンテンツ配信ネットワーク)

https://developers.google.com/speed/libraries/(最終閲覧2020/06/01)

Google Hosted Librariesにアクセスすると、以上の通り書いてある。無料で使用できるライブラリがホスティングされているというわけだ。jQueryのバージョンはこのようになっている。

つまり、先に書いた、

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>

このコードを入れてやることによってjQueryを読み込めるようになるということ。簡単だ。勿論、公式からjQueryライブラリをダウンロードする方法もある。

jQuery

ちょっとCDNが気になった

CDNとは何か。Content Delivery Networkという。「コンテンツをネットワークで効率的に配達する仕組み」、ということらしい。Google Hosted LibrariesにもCDNが使われているようだ。なので、サーバーにサイトから直接ファイルをダウンロードしてこなくても使えてしまうということ。ネット環境に左右されてしまうのがデメリットのようだが、基本的には上手く使えば便利だ。

中身(コード)を見ていく

中身をみていこう。
エディタにコード拝借して動作するのかローカルで試してみた。実際動いた。

試したらとりあえず動いた

HTML

htmlだけ見ると、こうなってる。

//html
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
</head>
<body>
<form><p><input type="button" id="start-button" value="Start" onClick="onStartButtonClick()">
<span id="message">Press Start</span></p></form>
<hr>
<div style="font-weight: bold;" id="word"> </div>
<div id="type"> </div>
</body>
</html>
出るのはこれだけ。シンプルだ。

JavaScript

JSを見ていく。まずはタイピングで使う単語をvar で定義している。これらが、ゲームで使うwordになる。wordListという変数が単語を表す。

// 単語
var wordList = [
    "Alfa", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India",
    "Juliett", "Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec", "Romeo",
    "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-ray", "Yankee", "Zulu"
];

次に時間制限を作る。timeLimitという変数に30を入れている。30秒ということだろう。この後、いくつか変数を定義しているが、何をしているのかはその後の処理を見ていかないとわからない。

// 時間制限
var timeLimit = 30;

ページをロードした時に、画像データなどよりも先に表示される。htmlの読み込みが完了後に実行される部分(window.onload)。

window.onload = function (){
    messageArea = document.getElementById("message");
    wordArea    = document.getElementById("word");
    typeArea    = document.getElementById("type");
    startButton = document.getElementById("start-button");
}

何をしているのか。ここでは、document.getElementById()で、htmlで指定したidに対応するElementオブジェクトを返している。例えば、id="message"に対応するオブジェクトをmessageAreaとしている。これで特定の要素に素早くアクセスすることが可能となる。この後で、これらに処理を加えていくことになる。

ここまでの内容

ここまでのJSで書かれているのは、
・ゲームで使う単語の定義
・そのほか、定数定義
・html読み込み後にElementオブジェクト返す
という感じだ。

オブジェクトとプロパティ

次はゲームの開始時間。
関数onStartButtonClick()では、まず先ほど設定したElementオブジェクトのmessageAreaついて、要素内のテキストにアクセスできるtextContentプロパティがついている。
プロパティとは何か。オブジェクトとプロパティについて。オブジェクトが持つことのできる情報のことをプロパティという。配列に近い。($messageArea[“textContent"] = “Ready?";のような感じ)
で、textContentは?このtextContentプロパティに似たようなものあるらしい。それがinnerHTMプロパティだ。違いは「HTMLを解釈」するか否かということだが、なんのこっちゃ。(innerHTM、textContentの違い

// 3秒後に開始
function onStartButtonClick(){
    messageArea.textContent = "Ready?";
    setTimeout("startTyping()", 3000);
}

なるほど。そういうことか。これを見れば分かる。

p1.textContent = "<b>ボタンを押しました</b>";//解釈しない、タグも含んでそのまま
p1.innerHTML = "<b>ボタンを押しました</b>";//解釈する、タグは表示しない

textContentではHTMLを解釈しないから、そのままタグもセットで表示される。対して、innerHTMLの方はHTMLを解釈するので、「ボタンを押しました」とだけ表示される。だから、今回のtextContentはHTMLを解釈せず、そのまま"Ready?"と出すわけか。でもタグが文字列に無いから同じか。

WindowOrWorkerGlobalScope

次は、setTimeout()。まず、WindowOrWorkerGlobalScopeのメソッドで、かつWindow.setTimeout()の後継。指定した時間が切れたときに実行したい動作を記述する。ここでの3000は3000ミリ秒を指す。つまり、3秒後に次の動作を実行する。
onStartButtonClick()はformのonClickに書いている。つまり、ボタンクリック3秒後に何をするかを表している。まず、クリック後にReady?という文字を出した後に、3秒後、startTyping()を実行するという流れ。
何をするのか。

// 開始
function startTyping(){
    score = 0;//得点
    timeLeft = timeLimit;//残り時間、30
    nextWord();//次の単語
    countDown();//残り時間
    timer1 = setInterval("countDown()", 1000);
    startButton.disabled = true;
}

クリック3秒後にゲームを開始する。
条件を記していく。
⓵開始の時点ではscoreは0にする。
②残り時間は、timeLeftでtimeLimitは先に定義した30。
そして、nextWord()。次の単語について。nextWord()の処理は以下のように書かれてある。

// 次の単語を表示
function nextWord(){
    charIndex = 0;//0
    var random = Math.floor( Math.random() * wordList.length );//整数(インデックス)
    wordArea.textContent = wordList[random];//何個目の配列、単語
    typeArea.textContent = "";//空文字セット
    wordChars = wordList[random].toUpperCase().split('');//打ち込んだものを大文字変換
}

Math.floor()、Math.random()

charIndex = 0; 文字の長さが0?
変数randomは、Math.floor()メソッドで出した整数。具体的には、「引数として与えた数以下の最大の整数を返す」。例えば、5.95なら5。5.05も5。-5.05は-6となる。その整数は、Math.random() * wordList.lengthの積で出されている。
Math.random()は「0以上1未満の範囲で、浮動小数点の擬似乱数」を返す。ふむ。

浮動小数点

浮動小数点とはなにか?これは、「計算で誤差が発生することを前提とした数値データ」とある。何かデータを出すときに、誤差を含んで考えるか、もしくは誤差は考えないで考える場合かあると思う。通常はプログラミングでは誤差は日常茶飯事。近似で、より結果の精度を意識しているということらしい。最大限誤差を意識した数字で、wordList.lengthをかけて整数を出している。wordListはタイプゲームで使う単語が格納されている配列。つまり、Array.lengthのことで、「値は符号なし32ビット整数」で、常に配列の最も大きなインデックスよりも数値的に大きくなる。なるほど、これで最大のインデックスに合わせているのか。

window.crypto.getRandomValues()

wordAreaは、id="word"のところ。wordList[random]は先ほど出した整数を入れて、対応するキーの単語を表示させる。ランダムで、何個目かの単語を出す。でも、ランダムというけど、Math.random()は推奨されないようだ。理由は、暗号に使用可能な安全性を備えていないから。代わりに、window.crypto.getRandomValues()メソッドを使用した方がいい。

toUpperCase()

タイピングの単語が大文字で出てきたけど、wordList[random].toUpperCase()で大文字に変換していたのか。正しくは、自分が打ち込んだワードが大文字になって画面に表示されている。
wordChars = wordList[random].toUpperCase().split(");で、打ち込んだwordを配列に。split(“"")で今回は空文字列にしているので、UTF-16 「文字」の配列になる。空文字にすると、サロゲートペア(2文字で1文字とみなす)を破壊するから注意しろとある。なんのこっちゃ?
とまあ、これでwordCharsを呼び出すときに使う。
さて、開始の関数に戻って、次の処理はcountDown();とある。

// 残り時間を計測
function countDown(){
    if(timeLeft <= 0) {
        stopTyping();
        return;
    }
    messageArea.textContent = timeLeft + " sec.";
    timeLeft--;
}

もしtimeLeft、残り時間が0以下になったら(0になったら)、stopTyping()を実行する。そして、残り時間を出す。stopTyping()は文字通り、ゲームの終了だ。

// 終了
function stopTyping(){
    clearInterval(timer1);
    wordChars = [];
    messageArea.textContent = "Score: " + score;
    wordArea.textContent = "";
    typeArea.textContent = "";
    startButton.disabled = false;
}

参照

[JS]Javascriptを使ったタイピングゲーム(最終閲覧2020/06/01)