여기서부터는 React를 이용한 화면 코드를 설명한다. client.js에서는 Main.js의 코드를 index.html의 root라는 id를 가진 div 태그에 렌더링 한다. Main.js부터 Main.js에서 사용하는 컴포넌트를 설명하겠다.
Main.js
import React, { useState, useEffect, useRef } from 'react';
import Chracter from './component/Character';
import Background from './component/Background';
import Enemy from './component/Enemy';
import { makeStyles } from '@material-ui/core';
import Button from '@material-ui/core/Button';
const useStyles = makeStyles(() => ({
root: {
},
button: {
border: '1px solid black',
margin: '50px 0 0 50px',
position: 'absolute',
width: '1000px',
height: '500px',
fontWeight: 'bold',
fontSize: '50px',
textTransform: 'initial'
},
timer: {
position: 'absolute',
display: 'flex',
left: '50px',
top: '570px',
fontSize: "20px"
}
}))
const Main = () => {
// Init
const updateTime = 20;
const interval = useRef();
// State
const [isStart, setIsStart] = useState(false);
const [time, setTime] = useState(0);
const [result, setResult] = useState(0);
const [isMove, setIsMove] = useState(false);
// 특정 시간을 주기로
// 1. Enemy에게 props로 보내는 state를 true 또는 false로 수정
// 2. 시간을 체크
// 3. 충돌을 체크
useEffect(() => {
if (isStart) {
interval.current = setInterval(() => {
if (Math.floor(time)%2 ==1){
setIsMove(true);
}else{
setIsMove(false);
}
setTime(time + updateTime * 0.001);
checkConflict();
}, updateTime)
}
return () => {
clearInterval(interval.current);
};
}, [time, isStart]);
// CSS
const classes = useStyles();
// 게임 시작
const handleClickStartButton = () => {
setIsStart(true);
}
// 충돌 체크하고 충돌이면 게임을 종료
const checkConflict = () => {
let enemy = document.querySelector('img#enemy');
let character = document.querySelector('img#character');
if (enemy !== null && character !== null) {
let dis = Math.pow(enemy.x - character.x, 2) + Math.pow(enemy.y - character.y, 2)
if (dis < 3000) {
alert("Game Over!");
if (result<time){
setResult(time);
}
setIsStart(false);
setTime(0);
}
}
}
// 시작한 경우 게임 컴포넌트를 렌더링
return (
<div >
{
isStart ?
<div>
<Background />
<Chracter />
<Enemy isMove={isMove}/>
<div className={classes.timer}>
<div >React Web Game!!</div>
<div style={{ margin: "0 0 0 50px" }}> Time : </div>
<div style={{ margin: "0 0 0 10px" }}>{Math.floor(time)}s</div>
</div>
</div>
:
<div>
<Button onClick={handleClickStartButton} className={classes.button}>
Your Highest Record is {Math.floor(result)}s
<br/>
Click to Start Game!!
</Button>
</div>
}
</div>
)
}
export default Main;
메인에서의 기능은 크게 네 가지이다.
첫 번째로 클릭하기 전에는 최근 가장 높은 점수를 보여주다가 클릭하면 게임을 실행시킨다. 게임의 진행 여부는 isStart라는 state에 저장하고 isStart 값에 따라 시작전 화면과 시작 후 화면을 구분하여 보여준다. 첫 화면을 마우스로 클릭하면 isStart값이 변하여 게임이 실행된다.
두 번째로 게임이 실행되면 얼마나 긴 시간 동안 세균을 잘 피하는지 체크하고 보여준다. 게임의 진행 시간은 time이라는 state에 저장하고 주기적으로 time값을 증가시키며 보여준다. time값이 증가할 때마다 증가한 time값을 보여주어야 하므로 처음 실행할 때와 time값이 변할 때마다 렌더링 하도록 설정해야 한다. 이를 위해 useEffect에서 특정 주기에 따라 time값이 증가하는 interval 함수를 실행하고 time값이 증가해 다시 렌더링 할 때 interval 함수를 없애도록 하였다.
세 번째로 주기적으로 time값을 증가시키는것 뿐만아니라 주기적으로 공룡과 세균이 충돌하는지 체크해야 한다. 이를 위해 useEffect에서 이전에 실행한 interval 함수 다음에 충돌을 체크하는 함수도 실행한다. 브라우저 상에서 공룡 이미지의 위치와 세균 이미지의 위치 사이 거리가 특정값 이하가 되면 게임을 종료한다.
네 번째로 주기적으로 세균을 등장시킨다. 공룡이 세균을 잘 피한다면 세균은 화면에서 사라지게 된다. 게임을 계속 진행하기 위해서는 다시 세균을 등장시켜야 하므로 세균 컴포넌트에 다시 등장하라는 값을 전달해야 한다. 세균 컴포넌트는 특정값이 true일 때만 움직이도록 설계를 하였고 세균이 화면 끝에 도달하면 이 값을 false로 설정하여 움직임을 종료한다. 이 값은 메인에서 isMove라는 state에 저장하며 이를 세균 컴포넌트의 props로 전달한다. 세균의 등장 주기는 3초마다 한 번으로 설정하였고 이를 위해 useEffect에서 주기적으로 isMove의 값을 true로 바꾼다.
다음으로는 Main에서 사용하는 컴포넌트들인 화면, 공룡, 세균 컴포넌트를 설명하겠다.
[전체 글]
'개인 개발 프로젝트 > 공룡 점프 게임' 카테고리의 다른 글
[공룡 점프 게임] 6. React 웹 게임 Heroku에 배포 (0) | 2020.07.21 |
---|---|
[공룡 점프 게임] 5. 공룡과 병균 컴포넌트 작성 (0) | 2020.02.02 |
[공룡 점프 게임] 4. 배경 컴포넌트 작성 (0) | 2020.02.02 |
[공룡 점프 게임] 2. React 앱 생성 및 설정 (0) | 2020.02.01 |
[공룡 점프 게임] 1. 프로젝트 소개 (2) | 2020.02.01 |