TS勉強

記入日:2023/10/21 17:29:10

blog thumbnail

はじめに

初投稿です。

最近TypeScriptを勉強したので、next.jsを使ってタイピングゲームを作りました。

作ったもの

デモ

https://typing-game-neco75.netlify.app

github

https://github.com/neco75/TypingGame-next.js

実装

今回は最低限の機能を実装することを目標にして、以下の要素を実装しました。

  • スコア機能
  • 制限時間
  • タイプした文字列の正誤判定

よくある1タイプごとに判定して、間違えている場合入力できない機能を実装したかったのですがうまくいきませんでした…

プロジェクトのセットアップ

最初に、新しいNext.jsプロジェクトを作成

npx create-next-app typing-game
cd typing-game

必要なライブラリをインストール

npm install react react-dom next

npm install typescript @types/react @types/node

npm install random-words

コード内容

プロジェクトの使わないファイルを消去、変更します。今回はcomponentsディレクトリを作成し、その下にTypingGame.tsxを用意しました。以下がindex.tsxとtypingGame.tsxのコードです

import React from 'react';

import TypingGame from '../components/TypingGame';

const Home: React.FC = () => {

  return (

    <div>

      <TypingGame />

    </div>

  );

};

export default Home;
import randomWords from 'random-words';

import React, { useState, useEffect } from 'react';

const TypingGame: React.FC = () => {

  const [word, setWord] = useState<string>('');

  const [input, setInput] = useState<string>('');

  const [score, setScore] = useState<number>(0);

  const [missCount, setMissCount] = useState<number>(0);

  const [time, setTime] = useState<number>(30);

  const [gameOver, setGameOver] = useState<boolean>(false);

  useEffect(() => {

    generateNewWord();

  }, []);

  useEffect(() => {

    let timer: NodeJS.Timeout;

    if (time > 0 && !gameOver && missCount < 5) {

      timer = setTimeout(() => {

        setTime(time - 1);

      }, 1000);

    } else if ((time === 0 || missCount >= 5) && !gameOver) {

      setGameOver(true);

      alert("Game Over");

    }

    return () => clearTimeout(timer);

  }, [time, gameOver, missCount]);

  const generateNewWord = () => {

    const newWord = randomWords();

    setWord(newWord);

    setInput('');

  };

  const reset = () => {

    setInput('');

    setScore(0);

    setMissCount(0);

    setTime(30);

    setGameOver(false);

    document.getElementById("text")!.style.backgroundColor = "white";

    generateNewWord();

  };

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {

    const userInput = e.target.value;

    setInput(userInput);

    if (!gameOver && missCount < 5) {

      if (userInput === word) {

        document.getElementById("text")!.style.backgroundColor = "white";

        setScore(score + 10);

        setTime(time + 2);

        generateNewWord();

      } else if (userInput.length >= word.length) {

        document.getElementById("text")!.style.backgroundColor = "pink";

        setInput('');

        setScore(Math.max(score - 1, 0));

        setMissCount(missCount + 1);

        if (missCount + 1 >= 5) {

          setGameOver(true);

          alert("Game Over");

        }

        setTime(Math.max(time - 3, 0));

      }

    }

  };

  return (

    <div>

      <h1>Typing Game</h1>

      <p>Time: {time}</p>

      <p>Score: {score}</p>

      <p>MissCount: {missCount}</p>

      <h2>Word: {word}</h2>

      <input id="text" type="text" value={input} onChange={handleInputChange} />

      <input id="reset" type="button" value="Reset" onClick={reset} />

    </div>

  );

};

export default TypingGame;

ゲームのロジック

ゲームの基本的なロジックは次のようになります。

  • タイピングされた文字列が正しい場合、スコアを増加させ、新しい単語を表示。
  • タイピングされた文字列が不正確な場合、スコアを減少させ、ミスカウントを増加
  • タイマーがゼロになるか、ミスカウントが5以上になるとゲームオーバーとなる

起動

サーバーを起動します。

npm run dev

デフォルトの http://localhost:3000 で実行されるはずです。

最後に

React自体殆ど触ったことなくてなかなか形にするのが大変でした。まだまだ改善点があるので、もう少し勉強したいです。