본문 바로가기

프로젝트/보드윗 (보드게임원 매칭 서비스)

[ 항해 99 실전프로젝트 ] 사용자의 아바타를 데이터로 만들자 ( 3 )

이미지를 동적으로 입히는 기능은 생각보다 단순했다.

이제는 사용자가 선택한 아이템들이 서버단에 저장이 되어, 새로고침 시나 로그아웃 후에 다시 로그인하여도 선택했던 아바타의 이미지가 나와야 한다.

 

 

우리가 정한 카테고리는 총 4가지로 좁혀봤다. 
  • 눈 (Eye)
  • 입 (Mouth)
  • 머리 (Hair)
  • 배경 (Back)

 

해야할 순서 
  1. 사용자가 여러 아이템들을 선택할 수 있는 슬라이드를 만들어준다.
  2. 슬라이드에 이미지들을 뿌려주기 위해, map함수를 사용해야하니 이미지파일규칙이 정해져야 한다.
  3. 슬라이드에서 선택한 아이템이 위 캐릭터에 반영이 되어야한다. (변수값이 공유되야함)
  4. 각종 카테고리별로 변수를 만들어, 선택된 아이템의 변수 값을 db로 쏴주어야한다.
  5. 여러 아이템들중, 하나만 선택했을 경우에도 정상작동해야한다. (조건문으로 할 지?_)

 

아이템 선택창

위와 같이, 이미지를 불러와서 아이템 선택창을 우선적으로 만들어주어야한다.

일일이 박스를 만들어 이미지경로를 정해주기는 너무 힘이드니, 일종의 파일이름에 규칙을 만들어 map함수를 사용해보려한다.

 

아래와 같은 방식으로 이름을 정하면 어떨까?

 

Eyewear_1

Eyewear_2

Eyewear_3

Eyewear_4

Eyewear_5

Eyewear_6

Eyewear_7

 

카테고리_순서.png 이런식으로 이름이 정해지면, db로 보낼때도 앞부분 카테고리와 순서를 보내면 되니 map함수를 돌릴때에도 간편할 것 같다.

 

그렇다면, 슬라이드에서 선택된 아이템이 캐릭터창에도 반영이 되게 props로 전달하면 될 것 같다.

 

 

import { style } from "@mui/system";
import React, { useState } from "react";
import AvatarBox from "./AvatarBox";
import styled from "styled-components";

const AvatarSelect = () => {
  //*초기 카테고리는 눈으로 고정
  const [selectCategory, SetSelectCategory] = useState("Eye");

  //! 이런식으로 user avatar가 db에 저장되면 된다!
  const userAvatar = { Eye: 1, Hair: 1, Mouth: 1, Back: 1 };

  const [userSelect, setUserSelect] = useState(userAvatar);
  const ImgList = [
    { Num: 1, Category: "Eye" },
    { Category: "Mouth", Num: 1 },
    { Category: "Mouth", Num: 2 },
    { Category: "Mouth", Num: 3 },
    { Category: "Mouth", Num: 4 },
    { Category: "Mouth", Num: 5 },
    { Category: "Mouth", Num: 6 },
    { Category: "Eye", Num: 3 },
    { Category: "Back", Num: 4 },
    { Category: "Eye", Num: 1 },
    { Category: "Hair", Num: 2 },
  ];
  console.log(userSelect);
  return (
    <Wrap>
      <AvatarBox userSelect={userSelect} />
      <AvatarSelectCtn>
        <AvatarCategory>
          <div
            className={selectCategory === "Eye" ? "selected" : undefined}
            onClick={() => SetSelectCategory("Eye")}
          >
            눈
          </div>
          <div
            className={selectCategory === "Mouth" ? "selected" : undefined}
            onClick={() => SetSelectCategory("Mouth")}
          >
            입
          </div>
          <div
            className={selectCategory === "Hair" ? "selected" : undefined}
            onClick={() => SetSelectCategory("Hair")}
          >
            머리
          </div>
          <div
            className={selectCategory === "Back" ? "selected" : undefined}
            onClick={() => SetSelectCategory("Back")}
          >
            배경
          </div>
        </AvatarCategory>
        <AvatarItemCtn>
          {ImgList.map((Img) => {
            if (Img.Category == selectCategory)
              return (
                <ImgItem
                  onClick={() =>
                    setUserSelect({ ...userSelect, [Img.Category]: Img.Num })
                  }
                >
                  {Img.Category}_{Img.Num}
                </ImgItem>
              );
          })}
        </AvatarItemCtn>
      </AvatarSelectCtn>
    </Wrap>
  );
};


export default AvatarSelect;

 

부모 컴포넌트에서 이러한 식으로, 이미지를 클릭하면 해당 카테고리의 숫자를 state값에 넘겨주고 자식컴포넌트에 넘겨준다. (객체의 키값을 동적으로 할당하기위해 빈 배열로 키값을 감싸줌) 

https://haardy.tistory.com/30

 

객체에 키값 동적으로 할당하기

객체로 만들 부분을 빈 배열로 만들고 [ ]방식으로 프로퍼티를 설정하는 방법을 이용하면 키 값을 동적으로 설정 할 수 있습니다. var keyname = "my"; var postfix = "Age"; var value = 27; var something = {}; somethi

haardy.tistory.com

여기서 자식컴포넌트는 아바타가 보여지는 박스이다. 그props를 받은 아바타박스는 이미지경로를 다시 설정하여 바뀐 아이템을 보여준다.

 

 

 

아래는 자식컴포넌트의 코드이다.

import React, { useState } from "react";
import styled from "styled-components";

const AvatarBox = ({ userSelect }) => {
  const [Face, setFace] = useState(1);
  console.log(userSelect);
  const { Eye, Hair, Mouth, Back } = userSelect;
  console.log(Mouth);
  return (
    <AvatarCtn>
      <BackCtn Back={Back}>
        {" "}
        <FaceCtn Face={Face}>
          <HairCtn Hair={Hair} />
          <EyeCtn Eye={Eye} />
          <MouthCtn Mouth={Mouth} />
        </FaceCtn>
      </BackCtn>
    </AvatarCtn>
  );
};



export default AvatarBox;

 

생각보다 간단하게 끝났다. 이때까지 잘 다루지 못한 이미지를 다룬다는 생각에 괜시리 어렵다 생각이 들었던 것 같다.

여기서 주목할만한 점은, background-image의 url을 변수를 활용해 동적으로 이미지 경로를 관리하는 것이다.

 

 

결과물

아직 이미지를 많이 만들어 놓지않아서, 선글라스 한 개랑 입술 두 개밖에 없지만 잘 구동하는 것을 볼 수 있다!