はじめに
初投稿です。
最近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のコードです
index.tsx
import React from 'react';
import TypingGame from '../components/TypingGame';
const Home: React.FC = () => {
return (
<div>
<TypingGame />
</div>
);
};
export default Home;
TypingGame.tsx
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自体殆ど触ったことなくてなかなか形にするのが大変でした。まだまだ改善点があるので、もう少し勉強したいです。