42Seoul의 마지막 과제로 실시간 퐁 게임(ft_transcendence)를 팀원 5명과 제작을 하였다.
약 3개월의 기간이 소요되었고 5명 모두 풀 스택으로 프로젝트를 진행하였다. 기술 스택은 React, tailwind, Recoil, Nest.js, Socket.io
이렇게 된다.
퐁 게임은 아주 간단한 게임으로 오픈 소스가 많이 있다. 그래서 '게임을 어떻게 구현을 해야하지?' 라는 두려움은 넣어두어도 좋을 것이다.
퐁 게임 홈페이지의 큰 기능들은 이렇게 나뉜다.
- 로그인 - 42seoul 의 계정을 통한 로그인
- 채팅방 - socket을 통한 채팅방 구현(+ 차단, 방출, 뮤트)
- 게임 - 롤의 랭게임처럼 게임을 등록하면 자동으로 다른 상대와 매칭 시스템과 온라인 유저에게 바로 게임 신청 할 수 있는 기능
그럼 게임 기능들 어떤 아이디어로 구현을 했고 어떤 어려움이 있었으며 어떻게 해결해 나갔는지 회고를 해보자.
게임 구현
게임 알고리즘은 깃허브 오픈 소스를 가져와서 우리에 맞게 바꿔서 사용을 하였다.
하지만 문제가 있다. react 오픈 소스는 모든 기능을 프론트에서 구현하게 되면 새로고침을 했을 경우 지금까지 플레이한 게임 정보가 없어지기 때문에 게임이 초기화가 되어버린다.
이 문제를 해결하기 위해서는 프론트와 백 파트를 분리해야한다. 백에 게임 데이터를 저장하고 socket으로 계속 데이터를 전송하면 새로고침을 해도 끊기지 않고 게임을 이어서 진행할 수 있다.
위 구조도를 보면 프론트엔드에서 처음에 게임 시작을 요청한다. 그러면 백에서 게임에 대한 기본적인 데이터 테이블을 생성하고 게임이 끝날 때까지 socket을 이용해서 계속 같은 유저에게 데이터를 전송하도록 하였다.
이렇게 구조를 바꾼 결과, 소켓이 재연결이 되면 계속 데이터를 받고 게임을 이어서 할 수 있게 되었다.
그리고 게임을 플레이하기 위해서는 key 조작도 동작을 해야하는데 key이벤트를 감지해서 back에 이벤트에 대한 정보를 보내서 back의 게임 바 위치 데이터를 변경하여 플레이 할 수 있도록 하였다.
발생했던 에러 및 해결법
1. 게임 생성과 게임에 대한 데이터를 프론트에서 받아오는데 시간이 오래걸림
- front : api 요청 최소한으로 구조 개편
- back : game 데이터 불러올 시 연관 없는 데이터 최대한 빼고 불어오도록 리펙토링
아쉬운 점
1. token의 httpOnly 미설정
게임 socket을 연결할 때 백에 token을 전달해주기 위해서 token을 socket을 생성할 때 같이 넣어줬는데, socket을 생성할 때 token을 넣어주려면 httpOnly가 해제가 되어있어야한다. 그래서 httpOnly를 해제시키고 사용을 했었다. http 같은 경우에는 자동으로 쿠키 token이 전달이 되어서 괜찮지만 socket의 경우에는 그렇지 못해서 어쩔 수 없이 httpOnly를 해제하였다.
이러게 되면 SQL injection이나 XSS의 공격에 취약할 수 있기 때문에 httpOnly로 바꾸고 리펙토링을 통해서 token이 필요한 경우에는 http 통신을 통해 증명하는 방향으로 바꿔야할 것 같다.
배운점
1. socket.io 사용법 및 WebSocket, HTTP 통신 차이점
WebSocket 방식과 HTTP 통신 방식의 차이점을 이해하고 어떤 상황에서 어떤 방식으로 기능을 구현하는 것이 좋을지 생각을 많이 해볼 수 있었다.
간단하게 정리하면 WebSocket을 써야하는 상황은 실시간으로 양방향 통신을 해야하는 pong game같은 경우에 사용하는게 좋다.
클라이언트는 실시간으로 변하는 데이터의 정보를 가져와야하는데 만약에 HTTP 통신 방식으로 한다고 하면 polling 방식으로 계속 HTTP 요청을 해야한다. 이렇게 되면 요청과 응답이 너무 많아지고 성능이 저하되는 문제가 있다. 하지만 WebSocket 방식으로 동작한다면 서버에서 연결되 socket으로 데이터만 계속 보내주면 되기 때문에 polling 방식보다 성능이 높아진다.
게임뿐만 아니라 채팅처럼 빠른 정보전달이 필요한 경우에 socket을 사용해서 데이터를 주고 받는게 좋다.
게임 경쟁전
경쟁전 같은 경우에는 queue에 유저의 소켓을 등록하는 방식으로 구현하였다.
순서
1. 클라이언트 A가 경쟁전을 등록한다.
2. 클라이언트 B가 경쟁전을 등록한다.
3. 경쟁전 queue에 2명 이상이 되면 앞에 2유저를 가지고 게임을 생성한다.
4. 게임의 고유 id를 가지고 room을 생성하고 room에 유저의 소켓을 등록한다.
5. socket room에 있는 유저들에게만 update된 게임의 내용을 계속 보내주면서 게임을 실행시킴.
발생했던 에러 및 해결법
1. normal, hard 모드 경쟁전 queue에 둘다 들어갈 수 있는 에러
- 같은 유저가 다른 브라우저로 등록을 한 경우 경쟁전 normal, hard 모드 queue에 둘다 들어갈 수 있는 에러가 발생한다.
이런 경우에는 에러처리하는 방법이 두가지가 있다.
a) 유저는 한 브라우저만 들어올 수 있도록 로그인을 할 때, online 상태이면 로그인을 하지 못하도록 처리한다.
b) 경쟁전 queue에 들어갈 때, 다른 모드의 경쟁전 queue에는 자신이 들어있지 않은지 확인하고 queue에 넣는다.
두가지 방법 중에 하나를 사용해서 에러처리를 하면 될 것 같다.
'42seoul' 카테고리의 다른 글
[42Seoul]멤버가 되고 나서 하는 miniShell(미니쉘) 회고 (0) | 2024.01.30 |
---|---|
[42Seoul] Web Server 프로젝트 회고 (0) | 2024.01.29 |
[42Seoul] Net_practice 문제풀이 (0) | 2023.07.13 |
[42Seoul] pipex (0) | 2023.07.02 |
[42Seoul] Born2beroot A-Z (0) | 2023.07.01 |