週刊アスキー連載: JavaScriptの部屋

ゲームでタイピングが驚きのスピードに!!

タイピング

Press Start button
(Target Text)


JavaScriptでタイピングゲームをつくります。

操作方法

タイピングに登場する主なメソッドなど

disabled
要素のdisabled(無効)属性を取得/変更するプロパティtrueに設定すると要素が無効、falseにすると要素が有効になる。
focus()
指定した要素にフォーカスをあてる。
style.top
要素のスタイル属性のとpプロパティを取得/変更するプロパティ
innerText
要素の中身(テキスト)を取得/変更するプロパティ
HTMLタグを反映しない。タグはそのままテキストとして表示される。「HTML」タグを反映したい場合はinnerHTMLを使用する。
clearInterval(タイマー)
setIntervalで作成されたタイマーを停止する。
charAt(文字位置)
文字列から指定した位置の文字を返す。
先読み位置は0。文字位置が文字列長を超える場合は空文字を返す。
slice(開始位置,終了位置)
指定した範囲の文字列を切り出す。
開始位置から終了位置の一文字前までの文字列を生成する。

HTML

<div class="hidden_area" id="status">Press Start button</div>
<div id="fall_area">
  <div id="target">(Target Text)</div>
<!--/#fall_area--></div>
<div class="hidden_area"></div>
<hr>
<form>
  <input type="text" id="in" size="80" oninput="typing()"><br>
  <input type="button" id="start" value="Start" onclick="startTyping()">
</form>

CSS

@charset "utf-8";
/* キータイピング */
#fall_area{
  position:relative;
  height:300px;
  background-color:#333333;
}
#target{
  font:bold 18pt 'Courier New';
  color:#FFFFCC;
  text-align:center;
  position:relative;
  top:-30px;
  z-index:1; /*一番奥*/
}
.hidden_area{
  height:30px;
  background-color:#000000;
  position:relative;
  z-index:2;
}
form{
  text-align:center;
}
#start{
  width:100px;
  margin:10px;
}
#status{
  line-height;
  color:#FFFFFF;
  text-align:center;
}

JS

//ゲームでタイピングが驚きのスピードに!!
//テキストを配列で管理
const array = [
"dog","apple","dandelion","hippopotamus","a vegetarian restaurant","Do you speak English?","No.I can't","The Early bird catches the worm.","Necessity is the Mothe of invention","if you can dream it, you can do it."
];

let index;

/*変数*/
let timer; /*タイマー*/
let posY; /*テキストの位置*/
let targetText; /*ターゲットテキスト*/
let checkText; /*チェック用テキスト*/
let score, bonus; /*得点,ボーナス得点*/

function startTyping(){
  //初期化
  index = 0;
  score = 0;
  bonus = 0;
  /*startボタンを無効化*/
  document.getElementById("start").disabled = true;
  document.getElementById("in").focus();
  //スタート
  setText();
}

function setText(){
  //ターゲットテキストの位置を上に変更
  posY = -30;
  document.getElementById("target").style.top = posY + "px";
  //ターゲットテキストをセット
  targetText = array[index];
  document.getElementById("target").innerText = targetText;
  
  //チェック用テキストにターゲット文字数の0をセット
  checkText = "";
  for(let i=0; i<targetText.length; i++){
    checkText += "0";
  }
  
  //問題数を表示
  document.getElementById("status").innerText = (index+1) + "/" + array.length;
  
  //0.05秒ごとにターゲットテキストを落下
  timer = setInterval(fall, 50);
}

function fall(){
  //ターゲットテキストの位置を落下
  posY +=1;
  document.getElementById("target").style.top = posY+"px";
  //300pxを超えると終了
  if(posY > 300){
    fallOut();
  }
}

function fallOut(){
  //入力欄をクリア
  document.getElementById("in").value="";
  //タイマーを停止
  clearInterval(timer);
  
  if(index < array.length -1){
    //次のテキストへ
    index++;
    setText();
  }else{
    //終了、得点発表
    document.getElementById("target").style.top = "100px";
    let scoreText = "SCORE: " + ("000000" + score).slice(-6);
    scoreText += "<br>BONUS: " + ("000000" + bonus).slice(-6)
    scoreText += "<hr>TOTAL: " + ("000000" + (score + bonus)).slice(-6);
    /*スコア表示*/
    document.getElementById("target").innerHTML = scoreText;
    document.getElementById("start").disabled = false;
  }
}

function typing(){
  //入力されたテキストを取得
  let inText = document.getElementById("in").value;
  
  //文字数をチェック(ターゲットテキストの文字数に制限)
  if(inText.length > targetText.length){
    inText = inText.slice(0,targetText.length);
    document.getElementById("in").value = inText;
  }
  //一文字ずつチェック
  for(let i=0; i<targetText.length; i++){
    if(i < inText.length){
      //チェック用テキストに「1」(正しい)または「2」をセット
      if(targetText.charAt(i) == inText.charAt(i)){
        checkText = checkText.slice(0,i)+"1"+checkText.slice(i+1);
      }else{
        checkText = checkText.slice(0,i)+"2"+checkText.slice(i+1);
      }
    }else{
    //未入力部分は「0」(未入力)をセット
    checkText = checkText.slice(0,i) + "0" + checkText.slice(i+1);
  }
}
//正しくタイプできた文字色を変更
let tempText = "";
let cnt = 0;
for(let i=0; i<checkText.length; i++){
  if(checkText.charAt(i) == "1"){
    tempText += '<font color="#00FF00">' + targetText.charAt(i) + '</font >';
    /*正しくタイプできた文字数をカウント*/
    cnt++;
  }else if(checkText.charAt(i) == "2"){
      //誤入力
      tempText += '<font color="#FF0000">' + targetText.charAt(i)+'</font>';
  }else{
    //未入力
    tempText += targetText.charAt(i);
  }
}
document.getElementById("target").innerHTML = tempText;
  //すべて正しくタイプできていれば終了
  if(cnt == targetText.length){
    //得点を加算、ターゲット位置をボーナス得点に加算
    score += cnt*100;
    bonus += (300 - posY)*100;
    fallOut();
  }
}