-
마피아 G 마스터 회고Project 2023. 11. 2. 14:11
마피아 G 마스터란 오프라인 마피아 게임을 위한 진행 가이드 서비스이다.
마피아 게임은 어렸을 때부터 간간이 해왔지만 내가 MC가 되어 진행한 적은 없었다. 이유는 마피아 게임의 규칙을 정확히 몰랐고, 혹시라도 역할을 까먹거나 진행을 실수하여 게임을 망치는 두려움도 있었기 때문이다. 이런 생각들을 줄줄이 늘어놓다 보니 나와 같은 사람이 있지 않을까 생각이 들었고 이 진행 가이드 서비스를 만들면 재밌겠다 싶어 시작하게 되었다.
디자인
주황 색상과 명도 대비
초기 생각했던 메인 색상은 주황이었다. 하지만 웹 접근성을 위해 주황 바탕에 흰 텍스트로 명도 대비를 검사해 보니 3:1 이하로 나왔다. 더 어두운 주황 계열의 색으로 바꾸면 되겠지만 그건 나의 미적 기준에 도저히 허용할 수 없었다. (...) 아쉽지만 메인 색상을 주황에서 빨강으로 바꾸게 되었다. 지금 생각하면 마피아의 이미지와 빨강이 워낙 잘 맞았기 때문에 결론적으론 좋은 선택이었던 것 같다.
추가로 주황색을 사용하는 서비스에 대한 레퍼런스를 찾아보다 보니 이 글을 보게되었다.
주황 바탕에 검은색 또는 흰색 텍스트에 대한 웹 접근성과 관련한 글이다.
개발
기술 스택
Next.js, TypeScript, Tailwind CSS, XState, Recoil, React Spring, PWA
XState
XState에 관한 기초 개념은 윗글에서 작성하였다.
마피아 게임은 밤과 낮으로 이루어진다. 밤에는 마피아가 시민을 죽이거나 의사가 누군가를 살리는 활동을 하게 된다. 낮이 되면 밤의 활동 결과를 토대로 토론을 진행하여 추방할 플레이어를 지목하게 된다. 밤과 낮이라는 유한한 상태를 가진다는 점을 이용하여 XState의 상태를 구성해 나갔다.
마피아 머신 statechart이다. 크게 start -> setting -> playing -> end의 구조로 이루어져 있다.
어느 상태에 있던지 뒤로가기를 누를 시 루트 페이지로 리다이렉션 되면서 초기화하는 clear 액션과 함께 start 상태로 돌아갈 수 있다. 이유는 뒤로가기를 누르면 이전 상태와 컨텍스트까지 복구가 되어야 하는 기대가 있는데 그렇지 않고 현재 상태에 머물러 있기 때문에 로직에 오류가 발생하게 된다. 만약 이전 단계로 돌아가야 하는 기능을 만들어야 한다면 어떤 접근으로 구현해야 하는지 고민을 해야할 것 같다.
playing 안에서 밤과 낮의 상태를 나누었다. 그중에 첫날밤에는 다른 밤과는 다르게 역할을 정해야 했기에 따로 분류하였다. 첫날밤에 플레이어 역할을 정한 후 낮에 토론과 추방, 밤에 지목하면서 게임을 진행하게 된다. 그리고 계속 always를 통해 살아있는 마피아와 시민의 수가 같아지거나, 살아있는 마피아가 모두 죽은 경우를 검사하여 이 경우가 참이면 end 상태로 트랜지션이 발생하게 된다.
always: { target: "end", cond: "isEnd", actions: ["setWinner"] }
Mobile First
이 서비스를 사용하는 사용자는 대부분 모바일 환경에서 사용할 것이란 예상이 들었다. 그렇기에 PC 환경보다는 모바일 환경에 집중하여 디자인과 개발을 진행하였다.
원래 height를 꽉 채우려 100vh를 사용하였지만, 모바일 환경에서 주소바를 포함하지 않아 스크롤이 생기는 이슈가 있어 100%로 변경하였다. (예전에 관련하여 글을 작성한 적도 있다.)
이 문제를 해결하기 위한 새로운 뷰포트 단위인 svh, lvh, dvh도 나왔다. 하지만 브라우저 호환성 이슈로 아직 적용하기에는 이른 시기인 것 같다.
설정에 들어서면 플레이어 닉네임을 정하는 input 속성에 autofocus로 설정하여 키패드가 자동으로 나오게 하였다. 그리고 만약 input을 통해 생성한 플레이어들이 내가 설정한 플레이어 수랑 동일하다면 isRequired state가 true가 되면서 버튼이 활성화된다. 이때 조건이 만족할 시점에 키패드가 자동으로 닫히게 하고 싶었다.
useEffect(() => { if (isRequired) inputRef.current?.blur() }, [isRequired])
useRef hook을 통해 input과 연결하고 isRequired가 true면 blur 메소드를 통해 input에 벗어나게 하였다.
또한 PWA도 적용하였다.
이후에도 리액트 네이티브를 통해 안드로이드 앱으로 구현해 보면 좋겠다는 생각이 들어 리액트 네이티브에 대해 알아보고 있다.
Lottie 번들
LottieFiles으로 적절한 애니메이션을 찾고 직접 lottielab을 통해 애니메이션을 만들어서 적용하였다.
@next/bundle-analyzer를 통하여 번들 크기를 분석하였을 때 lottie 파일이 프로젝트에서 가장 크게 차지하는 모습을 볼 수 있었다. 이를 최적화할 방안을 찾아보니 기존의 lottie-react 라이브러리를 사용하였는데 번들 크기를 감소시킬 수 있는 lottie-light-react 라이브러리가 있어서 기존 라이브러리 대신 적용하였다.
다시 분석을 해보니 번들 크기가 기존보다 43.78% 감소를 하였다.
그 밖에도 recoil이나 react-spring도 프로젝트에 처음 도입해 보았다. 또한 Storybook으로 버튼 컴포넌트를 작성하였는데 아무래도 혼자 개발을 하다 보니 필요성을 크게 느끼지 못하여서 계속 작성하진 못했다. 하지만 컴포넌트를 독립적인 환경에서 테스트하고 문서화할 수 있다는 점이 좋다고 느꼈다. 완성 후 최종적으로 Vercel을 통해 프로젝트를 배포하였다.
반응형'Project' 카테고리의 다른 글
[Chrome Extension] 크롬 확장 프로그램 Text Highlighter (2) 2023.06.09 ideal idea 회고 (0) 2023.04.03 MOVIE ROOM 회고 (0) 2023.02.12 인터랙티브 웹툰 Turn Off 회고 (0) 2023.02.06