Figma로 사격 맵 이미지 제작/적용

Ethan·2025년 4월 14일

2D로 원근감을 주는 맵 만들기

프로젝트 초기 세팅을 마치고 첫 번째로 진행한 작업은 맵을 구현하는 점이다.

단순하게라도 원근감 있게 맵을 제작하는 것이 중요했다. 3D로 게임을 구현하는 것은 지금의 내겐 큰 어려움이 있으니, 2D 이미지로 원근감을 주는 사격 게임의 맵을 구현해야 했다.

결과물


Figma를 사용해 조금의 노가다를 곁들여 기본 맵을 구현했다.

작아보일 수 있지만, 6440 X 3800의 상당한 크기다.
맵을 크게 구현한 건 1인칭 시점이다 보니 이동할 수 있는 시점의 각도가 어느정도는 자유로워야 FPS의 느낌을 살릴 수 있을 거라고 판단했다. 그래서 우선 크게 만들고, 확대한 시점을 적용해 여백을 확보할 수 있도록 크게 만들었다.

타겟은 중앙의 복도 끝 벽에 생성할 계획이다. 단순히 타겟이 허공에서 생성되는 것보다 여러가지 동작과 상호작용을 생각했지만, 실제로 구현하기는 어려운 것 뿐이라 기본적으로는 벽에서 타겟이 나타나도록 구현할 예정이다.

맵 이미지 적용

  // 이미지 크기 계산 함수
  const calculateImageSize = useCallback((canvas: HTMLCanvasElement, image: HTMLImageElement) => {
    const imageAspect = image.width / image.height;
    const canvasAspect = canvas.width / canvas.height;
    let drawWidth = canvas.width;
    let drawHeight = canvas.height;

    if (imageAspect > canvasAspect) {
      // 이미지가 더 넓은 경우
      drawHeight = canvas.width / imageAspect;
    } else {
      // 이미지가 더 좁은 경우
      drawWidth = canvas.height * imageAspect;
    }

    // 이미지를 배율
    drawWidth *= 2;
    drawHeight *= 2;
    drawSizeRef.current = { width: drawWidth, height: drawHeight };
  }, []);

  // 이미지 로드 함수
  const loadImage = useCallback(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    // 이미지가 이미 로드되어 있으면 크기만 재계산
    if (imageRef.current && imageRef.current.complete) {
      calculateImageSize(canvas, imageRef.current);
      return;
    }

    // 새 이미지 로드
    const image = new Image();
    imageRef.current = image;

    image.onload = () => {
      calculateImageSize(canvas, image);
      setImageLoaded(true);
    };

    image.onerror = (error) => {
      console.error('Failed to load image:', error);
    };

    image.src = '/map.svg';
  }, [calculateImageSize]);

전체화면 모드 기준으로 맵을 생성하는 코드 일부이다.
맵 이미지는 Canvas를 사용했다. 이미지를 쉽게 렌더링 할 수 있고, 빠른 시점 전환을 부드럽게 구현해야 해서 프레임을 그리기 쉬운 도구를 사용했다.

다음 할 일은 1인칭 시점을 구현하는 것이다.

profile
"Actions speak louder than words"

0개의 댓글