넘블에서 진행한 다른 색깔 찾기 게임 챌린지 참여!
https://www.numble.it/45cee9d3-49ad-4f67-9d2a-14607c2eeba7
✔ 구현 요구사항
- 각 스테이지마다 Math.pow(Math.round((stage + 0.5) / 2) + 1, 2)개의 사각형이 표시됨
- 한 스테이지의 제한 시간은 15초
- 스테이지 바뀔 때 마다 random으로 사각형의 색상을 적용, 하나만 다른색깔 적용(정답 사각형)
- 정답 사각형을 클릭한 경우 다음 스테이지로 넘어가고 Math.pow(stage, 3) * 남은시간 만큼의 점수가 누적, 오답을 클릭하면 제한시간 -3
- stage가 올라갈 수록 정답과 오답의 색상 차이가 줄어듬
✔ 사용한 라이브러리
- CRA : 초기 프로젝트 세팅
- emotion : 스타일 컴포넌트 사용(각 아이템 마다 크기와 색상을 props로 받아옴)
✔ 주요 구현 로직
- App.js에서 상태를 정의하고 관리
const [answer, setAnswer] = useState();
const [answerColor, setAnswerColor] = useState();
const [baseColor, setBaseColor] = useState();
const [isPlaying, setIsPlaying] = useState(true);
const [score, setSocore] = useState(0);
const [stage, setStage] = useState(1);
const [time, setTime] = useState(15);
const [itemList, setItemList] = useState([]);
- 게임 내에서 바뀌어야 되는 부분을 상태로 정의하고 관리 함
- 프로그램 시작 시 초기 세팅
useEffect(() => {
setIsPlaying(true);
// item 갯수
const itemCnt = Math.pow(Math.floor((stage + 1) / 2 + 1), 2);
// 0~ itme갯수 -1 사이의 숫자 중에서 난수 생성 -> answer 값으로 사용
const ans = Math.floor(Math.random() * itemCnt);
setAnswer(ans);
const baseColor = getBaseColor();
const getAnsColor = getAnswerColor(stage, baseColor);
console.log('baseColor : ', baseColor);
console.log('answerColor : ', getAnsColor);
setAnswerColor(getAnsColor);
setBaseColor(baseColor);
const tmpList = [];
for (let i = 0; i < itemCnt; i++) {
tmpList.push(i);
}
setItemList(tmpList);
}, [stage, isPlaying]);
useEffect(() => {
if (isPlaying) {
let timer = setInterval(() => {
setTime(time - 1);
}, 1000);
if (time <= 0) {
clearInterval(timer);
setTimeout(() => {
setTime(15);
alert(`GAME OVER! \n 스테이지 : ${stage}, 점수 : ${score}` );
setStage(1);
setIsPlaying(false);
}, 1000);
}
return () => clearInterval(timer);
}
}, [time, isPlaying]);
- 시작 시 사각형을 렌더링 하는 것을 itemList에 스테이지 마다 item 갯 수 만큼 배열로 관리 -> 이건 item의 key값으로 사용
- setInterval 이용해서 타이머 구현 스테이지 끝나고 다시 재시작하기위해 isPlaying 상태 정의
- 랜덤 컬러 지정 로직
const getBaseColor = () => { const ran1 = Math.floor(Math.random() * 255 + 1); const ran2 = Math.floor(Math.random() * 255 + 1); const ran3 = Math.floor(Math.random() * 255 + 1); return `rgb(${ran1}, ${ran2}, ${ran3})`; } const randomCalc = (num, ranNum) => { const flag = Math.round(Math.random()); if(flag == 1){ return ranNum + num; }else{ return ranNum - num; } } const getAnswerColor = (stage, baseColor)=> { const colorArr = baseColor.slice(4,-1).split(','); const num = Math.floor(Math.random() * (100-stage)+10); const ran1 = randomCalc(num, parseInt(colorArr[0])); const ran2 = randomCalc(num, parseInt(colorArr[1])); const ran3 = randomCalc(num, parseInt(colorArr[2])); console.log('num : ', num); return `rgb(${ran1}, ${ran2}, ${ran3})`; }
- answer컬러를 어떻게 지정할 지 고민을 좀 했음 내가 사용한 방법은
1. 우선 baseColor를 생성
2. 생성한 baseColor를 받아와서 컬러 값만 배열로 생성
3. 10~110 사이의 숫자 랜덤 생성 이 범위는 스테이지 올라갈 수록 점점 줄어듬
4. baseColor와 생성한 랜덤 숫자를 더하거나 혹은 빼거나를 랜덤으로 생성 -> 3번 반복해서 rgb값 생성
- 사각형 클릭 시 점수 처리
- 오답 클릭시 빠르게 여러번 클릭하면 점수가 0에서 안끝나고 -1, -2 이렇게 끝나서 0으로 끝나게 만들고 useEffect보면 setTimeout으로 1초 있다가 종료하게 만들었음const onSelect = useCallback((id) => { if (id === answer) { // 정답일 때 const newScore = score+(stage * stage * time); const newStage = stage + 1; setSocore(newScore); setStage(newStage); setTime(15); } else { // 아닐 때 if (time > 3) { setTime(time - 3); } else { setTime(0); } } },[time, itemList]);
- App.js 에서 주요 로직을 구현하고 props로 전달해서 header와 Board 컴포넌트를 렌더링
- 사각형 크기만 조절해서 렌더링 하면되서 Container랑 Item 컴포넌트 분리안하고 Board 컴포넌트에 한번에 작성함
✔ 어려웠던점 / 개선방안
- 사각형 렌더링 하는데 자동으로 사이즈를 조절할 수 있는 방법이 없을까 고민했는데 좋은 방법으로 구현하지 못했던 것 같음 개발자 도구 보고 Board Container 사이즈를 360 * 360으로 고정하고 stage 값을 받아와서 스테이지 마다 사각형의 가로 세로를 직접 계산해 줬음
const getLength = (stage) => { const divide = Math.floor(((stage+1)/2) + 1); const rst = (360 / divide) - 4; return rst; };
- 컴포넌트 최적화 하는 부분을 개선해야함
- timer 1초마다 Board 컴포넌트에 있는 하위 item이 전부 렌더링 됨 React.memo로 해결 하려 해봤는데 그대로 1초마다 계속 렌더링 된다
전체 코드!
https://github.com/HomieKim/React_PlayGround/tree/main/diff-color-game
'react' 카테고리의 다른 글
[React 상태관리] react-query 입문 하기 (0) | 2022.04.13 |
---|---|
react 무한스크롤 구현하기(react-intersection-observer, createAsyncThunk 사용) (0) | 2022.04.07 |
[React 상태 관리] useReducer 사용해 리팩토링 하기 (+ custom hook) (0) | 2022.03.30 |
[React 상태관리]리덕스 이해하기 + todoList 만들기 (0) | 2022.03.27 |
Zillow 클론코딩 회고 (0) | 2022.03.05 |
댓글