typing_gameを作成しました。

#what
シンプルなタイピングゲームを作成。

#why
HTML,CSS,JavaScriptの学習、理解を深めるため


#issue
・半角英数小文字のみ対応なので、全角日本語入力への対応。
・ミスタイプした際ライフポイントゲージが減り、０になるとゲームオーバーの機能。








```index.html
<!DOCTYPE html>
<html lang=ja>
  <head>
    <meta charset="utf-8">
    <title>Typing Game</title>
    <link rel ="stylesheet" href="css/styles.css">
  </head>
  <body>
    <p class="bg">
      <img src="bg.png" alt="背景"title="背景">
    </p>

    <div class="title">
      <p id="title">Typing Game</p>
    </div>
      
    <div class="target">
      <p id="target">click to start</p>
    </div>

    <p class="info">
      Letter count:<span id="score">0</span>
      Time left:<span id="timer">0.00</span>

      Miss type:<span id="miss">0</span>
    </p>

    <script src ="js/main.js"></script>
  </body>
</html>
```

```styles.css
body{
  font-family: 'Courier New',monospace;
  text-align: center;
  background-color: #b3b3b3;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
}

p.bg img{
  width: 100vw;
  height: 100vh;
  position: absolute;
  left: 0;
  top: 0;
  z-index: -1;
  -ms-filter: blur(6px);
  filter: blur(6px);
}

.title{
  font-size: 50px;
  margin-top: 50px;
  display        : inline-block;
  color          : #ffffff;            /* 文字の色 */
  font-size      : 36pt;               /* 文字のサイズ */
  letter-spacing : 4px;                /* 文字間 */
  text-shadow    : 
        2px  2px 9px #003366,
      -2px  2px 9px #003366,
        2px -2px 9px #003366,
      -2px -2px 9px #003366,
        2px  0px 9px #003366,
        0px  2px 9px #003366,
      -2px  0px 9px #003366,
        0px -2px 9px #003366;        /* 文字の影 */
}

.target{
  font-size: 48px;
  letter-spacing: 3px;
  background-color: rgb(161, 134, 255);
  width: 700px;
  padding: 40px;
  border-radius: 20px;

}

.info{
  display: flex;
  flex-direction: column;
}
```

```main.js
'use strict';
{
  const words = [
    'strawberry trapper',
    'guilty night,guilty kiss',
    'jumping heart',
    'hand in hand',
    'dreamer',
    'mirai ticket',
    'self control',
    'daydream worrior',
    'lonely tuning',
    'guilty eyes fever',
    'happy party train',
    'sky journey',
    'galaxy hide and seek',
    'innocent bird',
    'shadow gate to love',
    'landing action yeah',
    'my list to you',
    'miracle wave',
    'awaken the power',
    'crash mind',
    'drop out',
    'one more sunshine story',
    'water blue new world',
    'in this unstable world',
    'pianoforte monologue',
    'beginners sailing',
    'red gem wink',
    'white first love',
    'new winding road',
    'guilty farewell party',
    'thank you friends',
    'marine border parasol',
    'next sparkling',
    'hop stop nonstop',
    'believe again',
    'brightest melody',
    'jump up high',
    'deep resonance',
    'dance with minotaurus',
    'kokoro magic a to z',
    'wake up challenger',
    'new romantic sailors',
    'love pulsar',
    'changeless',
    'never giving up',
  ];

  let word;
  let loc;
  let score;
  let miss;
  const timeLimit = 30 * 1000;
  let startTime;
  let isPlaying = false;
  var type = new Audio('gun.mp3');
  var gameover = new Audio('correct.mp3');
  var misstyp = new Audio('ready.mp3');
  

  const target = document.getElementById('target');
  const scoreLabel = document.getElementById('score');
  const missLabel = document.getElementById('miss');
  const timerLabel = document.getElementById('timer');

  function updateTarget(){
    let placeholder = '';
    for (let i = 0; i< loc; i++){
      placeholder += '_';
    }
    target.textContent = placeholder + word.substring(loc);
  }

  function updateTimer(){
    const timeLeft = startTime + timeLimit - Date.now();
    timerLabel.textContent = (timeLeft / 1000).toFixed(2);

    const timeoutId = setTimeout(() =>{
      updateTimer();
    },10);

    if(timeLeft < 0){
      isPlaying = false;
      clearTimeout(timeoutId);
      timerLabel.textContent = '0.00';
      gameover.play(); 
      gameover.volume = 1.0;
      setTimeout(() =>{
        showResult();
      },100)
      target.textContent = 'click to replay';
    }
  }

  function showResult(){
    const accuracy = score + miss === 0 ? 0 :score/ (score + miss) * 100;
    alert(`${score} lettters.${miss}misses. ${accuracy.toFixed(2)}% accuracy!`);
    
  }

  window.addEventListener('click',() => {
    if(isPlaying === true){
      return;
    }
    isPlaying = true;

    loc = 0;
    score = 0;
    miss = 0;
    scoreLabel.textContent = score;
    missLabel.textContent = miss;
    word = words[Math.floor(Math.random() * words.length)];

    target.textContent = word;
    startTime = Date.now();
    updateTimer();
  });

  window.addEventListener('keydown', e => {
    if(isPlaying !== true){
      return;
    }

    if(e.key === word[loc]){
      type.play(); 
      type.currentTime = 0;
      type.volume = 1.0;

      console.log('score');
      loc ++;
      if(loc === word.length){
        word = words[Math.floor(Math.random() * words.length)];
        loc = 0 ;
      }
      updateTarget();
      score++;
      scoreLabel.textContent = score;
    }else{
      misstyp.play(); 
      misstyp.currentTime = 0;
      misstyp.volume = 1.0;
      console.log('miss');
      miss++;
      missLabel.textContent = score;
    }
  });
}
```

GitHubはこちらです。
https://github.com/izn303/TypingGame

ぜひ遊んでみてください！
http://izn5656.stars.ne.jp/typing_game/