#1 우당탕탕 Garden 페이지 개발 기록 - 설계와 초기 정원 맵 렌더링

💛 nalsae·2024년 1월 14일
1

💭 프로젝트 회고

목록 보기
5/7
post-thumbnail

 최근 Grow Story 서비스 개발을 진행할 때 필자는 정원 페이지를 전담하게 되었다. 그리고 정원 페이지의 핵심은 적립된 포인트로 나만의 정원을 꾸밀 수 있는 기능이다. 바로 다음과 같이 말이다.

 처음에는 쉽게 구현할 수 있을 거라고 생각했다. 그러나 디테일한 유저 시나리오까지 생각한다면 꽤 쉽지 않은 작업이었다. 간단한 예시를 들자면 다음과 같다.

👉 사용자가 정원 맵에 설치된 오브젝트를 클릭한 후

  1. 정원 맵의 설치가 가능한 곳을 클릭한다.
  2. 정원 맵의 설치가 불가능한 곳을 클릭한다.
  3. 정원 맵의 설치된 오브젝트를 클릭한다.
  4. 정원 맵이 아닌 다른 곳을 클릭한다.
  5. 클릭한 채로 저장 버튼을 클릭한다.
  6. 클릭한 채로 취소 버튼을 클릭한다.
    ...중략...

 이처럼 한 가지의 시나리오에 후순할 수 있는 경우의 수가 굉장히 많았고 그만큼 조건 및 예외 처리가 까다로웠다. 물론 게임 요소를 도입하기로 결정했을 때 각오한 바이긴 하고, 까다로운 만큼 구현했을 때의 성취감과 재미도 컸다.

 아무튼 이러한 이유로 처음부터 설계를 탄탄히 하고 개발에 들어가지 않으면 추후 추가 기능 개발 및 유지보수 시 굉장히 힘들어지겠다는 예감이 들었다. 그래서 개발에 앞서 사전 조사나 설계에 평소보다 시간을 투자했다. 그러나 유사한 기능을 구현한 웹 애플리케이션 레퍼런스는 거의 찾을 수 없었다. 어쩔 수 없이 0부터 쌓아올리자는 마음으로 차근차근 접근해보았다.


🤔 드래그? 클릭??

 가장 먼저 고려해야 할 핵심 기능은 오브젝트를 설치하고 이동시키는 것이다. 이를 구현하기 위해 두 가지 방식을 생각해볼 수 있겠다.

  1. 오브젝트를 드래그해서 원하는 위치에 드랍하는 방식
  2. 옮길 오브젝트를 클릭하고 원하는 위치에 다시 클릭하는 방식

 처음에는 1번, 즉 드래그 & 드랍 방식을 고려했었다. 그러나 모바일이 아닌 데스크탑 화면에서는 그만큼 맵의 크기가 커질 것이고, UX 관점에서 늘어난 맵의 크기에 따라 드래그 시 사용자가 느끼는 피로감이 비례하여 커지겠다는 생각이 들었다.

 또한 도입할 만한 드래그 & 드랍 관련 라이브러리를 조사했을 때 react-dnd와 react-beautiful-dnd가 있었는데, 우선 후자의 경우 하나의 리스트 내에서 세로 방향 드래그 & 드랍은 지원하지만 가로 방향의 드래그 & 드랍은 지원하지 않아서 도입할 수 없었다. 전자의 경우는 구현하려면 구현할 수는 있겠지만, 애초에 리스트 형태 안에서의 드래그 & 드랍 구현을 목적으로 만들어진 라이브러리라 구현하려는 기능을 위해 도입하기에는 적합하지 않아 보였다.

 이처럼 UX와 구현하려는 기능의 특성을 고려하여 상단 이미지처럼 오브젝트를 클릭하여 이동시키는 방식으로 기능을 구현하기로 했다.


🌍 맵을 생성해보자!

 기능 구현 방식도 정했겠다, 그 다음으로 생각해 볼 일은 오브젝트가 놓일 맵을 어떻게 생성할 것인가였다. 여기에도 두 가지 선택지가 있었다.

  1. <canvas> 요소를 이용하는 방식
  2. <div> 요소에 CSS grid를 이용하는 방식

 처음에는 <canvas> 요소를 이용하여 렌더링을 해볼까 생각도 했지만 프로젝트에 바로 도입하기에는 러닝 커브 문제도 있었고, 사용자가 자유롭게 배치하는 방식이 아니라 배치할 수 있는 구역이 정해져 있는 방식으로 기획되었기 때문에 CSS grid를 이용해보면 좋겠다는 생각이 들었다. 그래서 설계한 초기 맵은 다음과 같다.

 

 위와 같이 하나의 큰 <div>를 CSS grid로 생성하여 12개의 col, 8개의 row로 구분한다. 그러면 좌측 상단부터 각각의 구역의 좌표 값은 좌측 상단의 (x: 0, y: 0)부터 시작하여 우측 하단의 (x: 11, y: 11)이 된다.


🚩 위치 정보, 어떻게 저장하지?

 임의의 좌표 값을 설정했다면, 각 오브젝트별로 위치 정보를 어떻게 저장할 것인지 고민해야 했다. 이를 위해 백엔드 개발자 분과 소통하여 주고 받을 데이터 형식을 먼저 의논했다.

 정원 페이지에 접속하면 사용자의 고유 아이디 값을 토대로 RawGardenInfo라는 데이터를 요청한다. RawGardenInfo 데이터의 타입을 살펴보면 사용자의 닉네임 displayName, 사용자가 획득한 포인트 point, 사용자가 현재 가지고 있는 오브젝트 정보 plantObjs, 상점 렌더링에 사용할 products를 포함한다. 이 중에서도 특히 오브젝트의 정보가 담겨 있는 plantObjs 배열에 주목하면 다음과 같다.

 plantObjsPlantObj 객체로 구성된 배열이다. 다양한 프로퍼티를 포함하고 있지만 그 중에서도 위치 정보를 저장하는 핵심 역할은 location 객체가 담당한다. location 객체는 고유한 id 값 locationId, 오브젝트 설치 여부 isInstalled, x 좌표 값 x, y 좌표 값 y로 구성된다. 데이터와 함께 초기 맵 렌더링 로직을 간단히 설명하자면 다음과 같다.

  1. PlantObjs 배열을 순회하며 location 객체의 isInstalled에 접근한다.
  2. isInstalled 값이 true인 경우에만 맵 요소의 하위 요소로 <img>를 렌더링한다.
  3. 이때, 각 <img> 요소의 위치는 x, y 프로퍼티의 값에 따라 CSS의 top, left 값을 조작하여 결정한다.

🥳 초기 맵 렌더링 성공!

 짜잔! 렌더링 로직을 따라 위와 같이 정원 맵에 예쁘게 오브젝트들이 배치된 모습을 볼 수 있다. 초기 맵을 잘 생성했으니 다음에는 본격적으로 오브젝트를 이동시켜야 한다. 분량이 너무 길어질 것 같아서 다음 글에 이어서 다뤄보겠다.

👉 다음 글 보러 가기 - 오브젝트 설치와 이벤트 처리

profile
𝙸'𝚖 𝚊 𝚍𝚎𝚟𝚎𝚕𝚘𝚙𝚎𝚛 𝚝𝚛𝚢𝚒𝚗𝚐 𝚝𝚘 𝚜𝚝𝚞𝚍𝚢 𝚊𝚕𝚠𝚊𝚢𝚜. 🤔

0개의 댓글