첫번째 게임 prototype구성 - useReducer, useRef, transition/transform 사용
요새 이런저런거 공부한다고 막상 개발을 못해서 좀 답답했는데, 토요일 10시에 일어났기 때문에 어쩐지 지금 딱 개발하기 딱 좋다.
1. 현재 메인 화면에서 client-side navigation되는 부분이 없어서 이부분을 해줄거다. 첫번째 게임에 대해서만.
2. Tap Tap 동작이 있고, react에서 css animation을 적용할 것.
밤에 만든것
Component 기본 구성

지금 현재 큰 흐름은 이런식이다. index페이지에서 puzzle 컴포넌트로 연결하고, puzzle 페이지는 useReducer를 통해서 상태를 관리한다.
useReducer를 통한 상태 관리
// useReducer를 이용한 state 관리
const STATUS = {
LOADING: 0,
GAME_INTRO: 1,
GAME_STARTED: 2,
GAME_CANCELED: 3,
GAME_FINISHED: 4,
};
function reducer(state, action) {
switch (action.type) {
case "LOADING":
return { status: STATUS["LOADING"] };
case "GAME_INTRO":
return { status: STATUS["GAME_INTRO"] };
case "GAME_STARTED":
return { status: STATUS["GAME_STARTED"] };
case "GAME_CANCELED":
return { status: STATUS["GAME_CANCELED"] };
case "GAME_FINISHED":
return { status: STATUS["GAME_FINISHED"] };
default:
return state;
}
}
const Puzzle = () => {
const router = useRouter();
const [gameStatus, dispatch] = useReducer(reducer, {
status: STATUS["GAME_INTRO"],
});
const yesHandler = (e: React.TouchEvent | React.MouseEvent) => {
dispatch({ type: "GAME_STARTED" });
};
const noHandler = (e: React.TouchEvent | React.MouseEvent) => {
e.preventDefault();
dispatch({ type: "GAME_CANCELED" });
router.push("/");
};
////// more
이렇게 상태를 구성해서 gameStatus를 관리한다.
현재는 데이터를 받아오거나 하는것도 없어서 puzzle페이지에 들어가는 순간 상태는 STATUS["GAME_INTRO"] 이고 이때는 Modal컴포넌트를 렌더링한다. 이때 Modal 컴포넌트는 다른 게임에서도 사용할 수 있도록 Wrapping을 해주는 컴포넌트이고, yesHandler, NoHandler는 아래화면에서 yes, no를 선택했을때 상태를 업데이트 해주는 동작을 처리한다.

useRef를 통해서 Dom Element의 위치를 찾고, transition/transform 적용
Game 컴포넌트는 간단한 애니메이션이 적용된 게임이다.

이렇게 되어있는데, 애기들이 B를 탭하고 느낌표있는 곳을 탭을하면 애니메이션이 동작한다.
이때 해야하는 것은 B와 느낌표 박스의 위치를 먼저 찾는 것이다.
const answerRef = useRef<HTMLButtonElement>(null); // 정답으로 선택 될것
const targetRef = useRef<HTMLButtonElement>(null); // 이동해야하는 곳
useEffect(() => {
if (answerRef.current && targetRef.current) {
const answer = answerRef.current.getBoundingClientRect();
const target = targetRef.current.getBoundingClientRect();
setPosition({ x: target.left - answer.left, y: target.top - answer.top });
}
}, [answerRef, targetRef]);
이때 각 element의 위치는 useRef를 통해서 찾았다.
이렇게 하고나서 정답이 찾아진 순간 B 박스에 transition style을 아래와 같이 추가한다.
if (foundAnswer && selected === index) {
return (
<button
key={index}
className="cursor-pointer w-48 bg-red-50 border-solid border-8 border-red-500 flex justify-around items-center text-9xl font-extrabold text-red-500"
onClick={() => setSelected(index)}
style={{
...styles,
transform: `translate(${position.x}px, ${position.y}px)`,
}}
>
{op}
</button>
);
}
const styles = {
transition: `transform 2s ease-out`,
};
이 컴포넌트는 정답을 찾았을때 선택되어있는 박스에 스타일을 추가하는데 기본적인 style은 tailwindCSS를 통해서 적용했는데, transition 동작을 할건데 transform에 대해서만 할 수 있도록 transition: `transform 2s ease-out`, 을 적용했다. 그리고 실제로 어떻게 transform이 동작해야하는지는 inline 스타일에 x, y 좌표값을 계산해서 넘겨주었다.
이렇게 하면 스무스하게 박스에 animation을 처리하는 것을 볼 수 있다.
참고한 자료
https://www.youtube.com/watch?v=ztvNwFV0Ai0
https://webclub.tistory.com/481
transition(전이,화면 이동)
transition(화면 이동을 이용한 점진적 효과) transform(변환,변형) 효과도 재미있지만 CSS3의 transition 기능과 같이 결합하면 더 큰 효과, 생동감을 부여할 수 있습니다. transition 의 사전적 의미는 "전이,
webclub.tistory.com
https://codingbroker.tistory.com/54
[HTML, CSS] transform, transition으로 요소 이동 및 변형시키는 방법
CSS의 transform과 transition을 사용하여 html 요소를 이동 및 변형시키는 방법에 대해 살펴보겠습니다. transform 속성을 사용하여 효과를 주고 transition 속성으로 효과를 제어합니다. 예제를 통해서 살펴
codingbroker.tistory.com
후기
한 다섯시간 정도 삽질했을까.. 간단한 transform, transition관련한 부분을 React 컴포넌트에 어떻게 적용할지 감이 잘안와서 헤맸지만 animation을 잘적용하면 확실히 화면에서 할 수 있는것들이 많아질 것 같다.