2d 메타버스(게더타운)

민태홍·2022년 6월 19일
1
post-custom-banner

2d 메타버스 구현

코드

소켓이벤트를 통해 룸에 조인했음을 알리는 부분과 키보드 이벤트가 발생했을 경우 해당 위치로 캐릭터를 이동시키고 또 다른 캐릭터의 이동을 감지하여 이동시켜주는 부분의 코드이다.

 socket.emit('JOIN_ROOM', { id: socket.id, cId: 0 }, (userData: any) => setUser(userData));
    socket.on('makeRoomClient', (RoomUser: any) => setUsers(RoomUser));

    handleMove.addEventListener('keydown', (event) => {
      if (Object.keys(keyboardEvent).includes(event.code)) {
        setTempBackground((v: any) => {
          return keyboardEvent[event.code].background(v);
        });
        setUser((v: any) => keyboardEvent[event.code].character(v));
      }
    });

    handleMove.addEventListener('keyup', () => setUser((v: any) => ({ ...v, state: 'mid' })));

    socket.on('changeMove', (list: any, temp: any) => {
      setUsers(list);
      if (temp !== null)
        (function () {
          setBackground((v: any) => temp ?? v);
          setMove(false);
        })();
      else setMove(true);
    });

백그라운드 이미지를 캐릭터 이동에 따라 해당하는 부분을 그려주는 코드이다.

 useEffect(() => {
    const context = canvasBackgroundRef.current?.getContext('2d');
    background.src = testMap;
    background.onload = () => {
      context?.drawImage(
        background,
        -marginBackground.left / 2,
        -marginBackground.top / 2,
        window.innerWidth,
        window.innerHeight,
        0,
        0,
        window.innerWidth * 2,
        window.innerHeight * 2,
      );
    };
  });

  useEffect(() => {
    const context = canvasBackgroundRef.current?.getContext('2d');
    context !== null && context.clearRect(0, 0, window.screen.width, window.screen.height);
    context?.drawImage(
      background,
      -marginBackground.left / 2,
      -marginBackground.top / 2,
      window.innerWidth,
      window.innerHeight,
      0,
      0,
      window.innerWidth * 2,
      window.innerHeight * 2,
    );
  }, [marginBackground]);

캐릭터가 이동햇을 경우 모션과 이미지를 바꿔주는 역할을 하고 위치를 수정해주게 된다.

  const characterCanvas = useRef<any>(null);

  const changeMotion = (direction: any, state: any) => dance[state] ?? direct[direction] + run[state];

  const [characterImg, setCharacterImg] = useState<any>();

  useEffect(() => {
    setCharacterImg(new Image());
  }, []);

  useEffect(() => {
    if (!characterCanvas.current) return;
    const actx = characterCanvas.current.getContext('2d');
    actx.clearRect(0, 0, window.innerWidth, window.innerHeight);
    Object.entries(users).map(([key, { x, y, direction, state }]: any) => {
      if (key !== socketId) {
        if (characterImg === undefined || !characterImg) return;
        characterImg.src = Yukey;

        actx?.drawImage(
          characterImg,
          changeMotion(direction, state),
          0,
          32,
          32,
          window.innerWidth / 2 + x - users[socketId].x,
          window.innerHeight / 2 + y - users[socketId].y,
          50,
          50,
        );
      } else {
        if (characterImg === undefined) return;
        characterImg.src = Yukey;

        actx?.drawImage(
          characterImg,
          changeMotion(direction, state),
          0,
          32,
          32,
          window.innerWidth / 2,
          window.innerHeight / 2,
          50,
          50,
        );
      }
    });
  }, [characterImg, users]);
post-custom-banner

0개의 댓글