추억의 두더지게임으로 화면에 두더지가 랜덤으로 나타나면, 두더지를 클릭하여 점수를 획득하는 게임이다.
npx create-react-app molegame --template basic-react
import React from 'react'
import moleImg from '../images/mole.png'
import '../index.css'
export default function Mole({show}) {
return (
<img src={moleImg} alt="mole" className={`mole ${show ? 'show' : 'hidden'}`}/>
)
}
import React, { useState, useEffect } from 'react';
import Mole from './Mole';
import moleImg from '../images/mole.png'
import '../index.css';
export default function MoleGame() {
const [moles, setMoles] = useState(Array.from({ length: 5 * 5 }, () => false));
const [isGameRunning, setIsGameRunning] = useState(false);
//두더지 클릭시 점수
const [score, setScore] = useState(0)
const moleClickScore = () => {
setScore(score+1)
}
//타이머 30초
const [time, setTime] = useState(30)
useEffect(() => {
let moleInterval;
if (isGameRunning) {
// 게임시작, 랜덤 두더지 나오기
moleInterval = setInterval(() => {
const randomIndex = Math.floor(Math.random() * moles.length);
const newMoles = [...moles];
newMoles[randomIndex] = true;
setMoles(newMoles);
// 0.5초 후에 두더지 다시 숨김
setTimeout(() => {
newMoles[randomIndex] = false;
setMoles(newMoles);
}, 500);
setTime((prevTime)=>{
if(prevTime === 1){
alert(`짝짝짝! 점수는 ${score} 입니다.`)
setIsGameRunning(false)
setScore(0)
return 30
}
return prevTime - 1
})
}, 500);
}
return () => {
clearInterval(moleInterval);
};
}, [isGameRunning, moles, score]);
const startGame = () => {
setIsGameRunning(true);
};
const stopGame = () => {
setIsGameRunning(false);
};
const endGame = () => {
setIsGameRunning(false);
setMoles(Array.from({ length: 5 * 5 }, () => false))
setScore(0)
setTime(30)
}
return (
<div className='wrap'>
<div className='moleTit'>
<h1>
추억의<img src={moleImg} alt='logo'/><br/>
두더지 게임
</h1>
<div className='startEnd'>
<button onClick={startGame} type='button' disabled={isGameRunning}>
Start
</button>
<button onClick={stopGame} type='button' disabled={!isGameRunning}>
Stop
</button>
<button onClick={endGame} type='button'>
End
</button>
</div>
<div className='moleScoreTime'>
<button type='button'>Score : {score}</button>
<button type='button'>Timer : {time}</button>
</div>
</div>
<div className='moleList'>
<ol>
{moles.map((show, index) => (
<li key={index} onClick={()=> show && moleClickScore()}>
<Mole show={show} />
</li>
))}
</ol>
</div>
</div>
);
}
* {margin: 0; padding: 0;}
button {
cursor: pointer;
background: none;
border: 0;
}
.wrap {
padding: 3% 1%;
display: flex;
flex-direction: column;
width: 100%;
gap: 20px;
max-width: 500px;
margin: auto;
}
.moleList {
margin: auto;
border-radius: 10px;
background: #9ec15e;
}
.moleList ol {
display: grid;
grid-template-columns: repeat(5, 0fr);
list-style: none;
}
.moleList li {
width: 100px;
height: 100px;
}
h1 {
text-align: center;
color: rgb(116, 78, 54);
}
h1 img {width: 50px;}
img {
width: 100%;
vertical-align: top;
}
.startEnd {
padding-top: 3%;
display: flex;
justify-content: center;
gap: 10px;
}
.startEnd button {
border: 0;
color: #fff;
width: 70px;
font-size: 1rem;
border-radius: 10px;
height: 40px;
background: brown;
}
.moleScoreTime {
padding-top: 4%;
display: flex;
justify-content: space-around;
}
.moleScoreTime button {
color: #562706;
font-size: 1.2rem;
}
.mole {
height: 0;
cursor: pointer;
transition: transform 0.2s ease-in;
transform: translateY(50%);
}
.mole.show {
transform: translateY(0);
height: 100px;
}
@media (max-width: 500px) {
.wrap {padding: 10% 1%;}
.moleList li {
width: 60px;
height: 60px;
}
.mole {
transform: translateY(20%);
}
.mole.show {
transform: translateY(0);
height: 60px;
}
}
useState
훅으로 게임시작,중단 점수,타이머 상태 관리useEffect
훅으로 게임루프를 설정하고 관리- 게임 시작, 일시정지, 종료 함수로 게임 상태 구현
- css로 두더지 나타남과 숨김 애니메이션
setTimeout(() => {
newMoles[randomIndex] = false;
setMoles(newMoles);
}, 500);
setTime((prevTime)=>{
if(prevTime === 1){
alert(`짝짝짝! 점수는 ${score} 입니다.`)
setIsGameRunning(false)
setScore(0)
return 30
}
return prevTime - 1
})
setTimeout 함수는 비동기적으로 동작하기 때문에 prevTime이 업데이트 되기전에 값으로 사용되서 29로 나온거였다.
setTimeout바깥으로 setTime을 분리해주었고, 타이머가 1초 남았을 때, 게임 종료 알림(alert)을 띄우고, 게임 상태를 초기화하도록 수정했다.
추가/수정할 기능
- 타이머 줄어들수록 랜덤한 두더지 나오는 속도 증가
- 두더지 한개씩말고, 랜덤으로 여러개 나오기
- 점수 최고점 설정하기
- Stop클릭시 두더지클릭 및 점수 반영 안되게 하기
- 같은 두더지는 한번이상 클릭 안되기
- 컴포넌트 더 분리하기 타이머, 게임컨트롤..
리액트로 간단한걸 만들고싶어 어떤걸 만들지 고민하다 게임을 생각했고, 추억의 두더지게임으로 정했다.
//두더지 생성
//두더지 클릭이벤트
//게임 점수 상태관리
이런식으로 주석으로 구현할 기능 부터 정리하고, 시작했다.
코드는 짜고보니 간단한데, 수정의 수정을 거듭하여..대략 2시간 좀 넘게 걸렸다. 그래도 오랜만에 리액트로 혼자 이것저것 만들어보니 좀 익숙해진것도 같다...🤓;
이제 코드 중복되는것 정리하고, 리팩토링 내용도 블로그에 업뎃해야겠다.