React로 주사위 만들기

nd098pkc·2023년 2월 7일
1

Dice

목록 보기
1/1

리액트로 주사위를 만들어보자-1

개요

CSS 애니메이션과 렌더링 최적화 공부에 도움이될만한 프로젝트를 고민해보던 중 주사위 굴리는 모션을 직접 구현해보면 좋겠다는 생각이 들었습니다.
CSS로 애니메이션을 입히는 작업 자체는 크게 어려운 일이 아니지만 주사위가 굴러가는 모습을 얼마나 정교하게 구현할 것인가에 따라 굉장히 난이도가 높아질 수 있겠다는 생각이 듭니다.
구현해나가면서 부딪히는 고민이나 어려운점들을 정리해보고자 합니다.

1. 정육면체 만들기

우선 주사위 모양을 3d로 만들어보겠습니다.
CSS를 통해 3d 입체 모형을 내는것은 그리 어렵지 않습니다.

브라우저에서 Width에 해당하는 방향이 X축, Height에 해당하는 방향이 Y축, XY 평면과 수직을 이루는 축이 Z축이 됩니다.
출처: https://nixpluvia.tistory.com/23

주사위의 6면을 감쌀 컨테이너에 "transform-style: preserve-3d"를 지정해준 뒤 각 면에 transform을 이용하여 특정 방향으로 이동시키고 싶을 경우 translate(X or Y or Z)를, 특정 축을 중심으로 회전시키고 싶으면 rotate(X or Y or Z)를 지정해주면 됩니다.
기본적으로 요소는 XY평면에 평행하므로 X축을 중심으로 90도 회전시키면 XZ평면에 평행, Y축을 중심으로 90도 회전시키면 YZ축에 평행하게 되는것을 알 수 있습니다.

출처: 위키백과(https://ko.wikipedia.org/wiki/%EC%A0%95%EC%9C%A1%EB%A9%B4%EC%B2%B4)

정육면체에는 총 6면이 존재하고, XY평면에 평행한 면 2개(앞, 뒤), XZ평면에 평행한 면 2개(위, 아래), YZ평면에 평행한 면 2개(좌, 우)가 필요하므로 회전시키지 않은 면 2개, X축을 중심으로 회전시킨 면 2개, Y축을 중심으로 회전시킨 면 2개가 필요합니다.
그리고 각 면을 만들고자하는 정육면체의 크기만큼 평행한면에 수직방향으로 간격을 벌려주면 되겠습니다.

정육면체 위치에 따른 각 요소의 Transform 값(정육면체 크기 : 60px)
  FRONT: translateZ(30px),
  BACK: translateZ(-30px),                      //앞면과 뒷면은 각각 30px씩 앞뒤로 이동만 시켜줌
  RIGHT: translateX(30px) rotateY(90deg),       
  LEFT: translateX(-30px) rotateY(-90deg),      //Y축을 중심으로 회전시킨 좌,우면은  YZ평면에 평행하므로 
  수직이 되는 X축 방향으로 이동
  TOP: translateY(-30px) rotateX(90deg),
  BOTTOM: "translateY(30px) rotateX(-90deg),   //X축을 중심으로 회전시킨 상,하면은  XZ평면에 평행하므로 
  수직이 되는 Y축 방향으로 이동
// Side.tsx
function Side({direction}: {direction: DiceSide}) {
return (
  <div
    css={css`
      width: 60px;
      height: 60px;
      position: absolute;
      top: 0;
      left: 0;
      background: white;
      border: 1px solid black;
      border-radius: 3px;
      display: flex;
      justify-content: center;
      align-items: center;
      transform: ${DICE_SIDE_TRANSFORM[direction]}; <-상수로 transform값 저장해둠
    `}>
    {direction}
  </div>
);
}

그렇게 정육면체를 완성시켜봤지만 앞면만 보이니 정육면체인지 사각형인지 구분이 안가는군요
컨테이너자체를 조금 회전시켜서 측면을 보겠습니다.

 // Dice.tsx
function Dice() {
  return (
    <div
      css={css`
        width: 60px;
        height: 60px;
        position: absolute;
        perspective: 100rem;
        transform-style: preserve-3d;
        transform: rotateY(25deg) rotateY(25deg) rotateZ(25deg); <--각 축으로 조금씩 회전
      `}>
      <Side direction={DICE_SIDES.FRONT} /> 
      <Side direction={DICE_SIDES.BACK} />
      <Side direction={DICE_SIDES.RIGHT} />
      <Side direction={DICE_SIDES.LEFT} />
      <Side direction={DICE_SIDES.TOP} />
      <Side direction={DICE_SIDES.BOTTOM} />;
    </div>
  );
}

정상적으로 정육면체가 만들어진것을 확인했습니다.
그럼 이제 이제 이 정육면체를 주사위라 부르기로 하고 슬슬 이 주사위를 굴려보도록 하겠습니다.

profile
늦게배운 코딩이 무섭다

0개의 댓글