Realtime WebGame 개발
WebSocket을 응용하여 뱀파이어 서바이벌류 웹 게임에 서버를 연결하여 스테이지 관리 아이템 시스템을 구현해보려 한다!
구현 목표
-
스테이지의 구분
- 클라이언트의 일정 점수/시간이 지나면 서버에 요청하여 스테이지가 달라져야 함
-
스테이지에 따른 점수 획득 구분
- 스테이지가 올라갈수록 획득하는 점수가 달라져야함
-
스테이지에 따라 아이템 생성
- 아이템이 스테이지 정보에 따라 생성될 수 있게 설계
-
아이템 획득 시 점수 획득
-
아이템 획득 시 서버의 검증 뒤에 획득
-
추가로 아이템 생성 시간을 이용하여 어뷰징 행위 방지 기능
-
-
아이템 별 획득 점수 구분
- 아이템에 따라 획득하는 점수가 달라야 하며, 이를 서버에서 검증해주어야 함
(획득 점수, 획득 스테이지)
- 아이템에 따라 획득하는 점수가 달라야 하며, 이를 서버에서 검증해주어야 함
-
Broadcast 기능 추가
- 모든 유저에게 알릴 수 있는 기능 추가하기 (실시간 채팅?서버 알림?)
-
가장 높은 점수 Record 관리
-
가장 높은 점수는 현재 클라이언트에서 저장되고 있으나, 이를 서버에서 관리하는 형태로 수정
-
서버에서 가장 높은 점수가 갱신되면 현재 게임에 참여한 유저들에게도 알려주어야 함
-
-
유저 정보 연결
-
유저 ID를 클라이언트가 알고 있다면, 다음 접속부터 이전 게임 기록에 연동이 가능하여야 함
=> 로그인/회원가입 기능?
-
-
Redis 연동, 게임 정보 저장
- 유저, 스테이지 (세션) 정보를 redis에 저장해보기
기획
게임에서 시간이 지날 때마다 점수가 올라가며 15분을 버티면 승리하도록 설계
-
만약 플레이어의 체력이 0이 되면 게임 오버되며 최고 점수를 클라이언트/서버 에 저장
(체력은 최대 3이다 => 피격 3번 당하면 골로감) -
클라이언트가 일정 시간을 넘어가면 서버에 요청을 통해 다음 스테이지로 이동
(이 때 서버는 이전 스테이지와 현재시간을 통해 검증) -
스테이지가 올라갈 수록 획득하는 점수가 증가함 (아이템, 시간)
-
스테이지가 올라갈 수록 아이템의 종류가 증가하거나 감소함 ( 아이템은 회복/점수/스탯 관련으로 기획 )
-
게임 진행 중 채팅을 통해 서버에 접속한 인원들과 대화 가능 ( 접속 시에 닉네임 추가 기능?)
-
서버에서 최고점 갱신이 확인되었을 시, 서버에 참여한 전 인원에게 관련 메시지를 보냄
-
클라이언트 접속 시, 유저를 분별할 수 있는 ID를 받도록 설정하여 이전 기록들을 확인할 수 있도록 설계
(이전에 서버 최고 기록 달성을 한 적이 있다면 전용 메시지도 같이?)
Packet 구조 설계
- 웹소켓을 통해 주고 받을 Date의 구조를 정해주어 서버와 클라이언트에서 송/수신 할 때 알맞게 변환/해석할 수 있도록 한다.
| Field | Type | Description |
|---|---|---|
| handlerId | INT | 요청을 처리할 서버 핸들러의 ID 값 |
| userId | INT | 요청을 보낸 유저의 ID 값 |
| clientVersion | STRING | 클라이언트의 버전 관리용 값 |
| payload | JSON | 요청 시 서버에게 보내줄 데이터 |
- Payload - 스테이지 이동
| Field | Type | Description |
|---|---|---|
| currentStage | INT | 현재 스테이지의 레벨 |
| targetStage | INT | 이동할 다음 스테이지의 레벨 |
| score | INT | 서버에서 검증할 때 사용할 현재 점수 |
- Payload - 아이템 획득
| Field | Type | Description |
|---|---|---|
| item | OBJECT | 획득하는 아이템의 정보 |
- Payload - 유저 정보 (첫 접속, 사망, 클리어 시)
| Field | Type | Description |
|---|---|---|
| userId | UUID | 유저의 고유 ID |
| nickname | STRING | 유저의 닉네임 |
| Score | INT | 유저의 점수 |
Data Table 설계
- Data Table을 관리하는 방법으론 file / DB / CDN 등이 있으나, 간단한 프로젝트이기에 일단 file 형식으로 관리할 예정이다!
| Field | Type | Description |
|---|---|---|
| name | STRING | 테이블의 이름 |
| version | STRING | 테이블의 버전 |
| data | JSON | 테이블에 저장되어 사용되는 정보 |
-
DATA - Stage
Field Type Description level INT 스테이지의 레벨 time INT 스테이지 진입에 필요한 시간(단위: 초) scorePerSecond INT 스테이지의 초당 획득하는 점수 ID color STRING 스테이지의 체크무늬 색 (헥사 색상 코드) spawn INT 10초당 생성될 몬스터의 수 { "name": "stage", "version": "1.0.0", "data": [ {"level":1,"time":0,"scorePerSecond":1,"color":"#C4F0AB","spawn":25}, {"level":2,"time":30,"scorePerSecond":3,"color":"#E9F0AB","spawn":25}, {"level":3,"time":60,"scorePerSecond":5,"color":"#F0D2AB","spawn":27}, {"level":4,"time":90,"scorePerSecond":7,"color":"#F0B4AB","spawn":30}, {"level":5,"time":120,"scorePerSecond":10,"color":"#ABF0DC","spawn":25}, {"level":6,"time":150,"scorePerSecond":13,"color":"#ABE0F0","spawn":15}, {"level":7,"time":180,"scorePerSecond":15,"color":"#ABABF0","spawn":20}, {"level":8,"time":210,"scorePerSecond":18,"color":"#CEABF0","spawn":15}, {"level":9,"time":240,"scorePerSecond":25,"color":"#F0ABE5","spawn":18}, {"level":10,"time":270,"scorePerSecond":35,"color":"#F0ABCE","spawn":15} ] } -
DATA - Item
Field Type Description id INT 아이템의 고유 ID score INT 획득 시 얻게되는 점수 health INT 획득 시 회복되는 체력량 damage INT 획득 시 증가하는 공격력 attackSpeed INT 증가하는 초당 발사 속도 speed INT 획득 시 증가하는 이동속도 prob INT 몬스터를 죽였을 시 드랍되는 확률 color STRING 아이템의 구분용 색 (헥사 색상 코드) { "name": "item", "version": "1.0.0", "data": [ {"id":1001,"score":20,"health":0,"damage":0,"attackSpeed":1,"speed":0,"prob":15,"color":"#006666"}, {"id":1002,"score":5,"health":1,"damage":2,"attackSpeed":1,"speed":0,"prob":5,"color":"#009999"}, {"id":1003,"score":25,"health":0,"damage":2,"attackSpeed":0,"speed":2,"prob":20,"color":"#00CCCC"}, {"id":1004,"score":100,"health":1,"damage":3,"attackSpeed":0,"speed":1,"prob":4,"color":"#00FFFF"}, {"id":1005,"score":1000,"health":1,"damage":3,"attackSpeed":0,"speed":1,"prob":5,"color":"#CCCC00"}, {"id":1006,"score":10,"health":2,"damage":1,"attackSpeed":3,"speed":1,"prob":1,"color":"#FFFF00"} ] } -
DATA - Monster
Field Type Description id INT 몬스터의 고유 ID health INT 몬스터의 체력 defense INT 몬스터의 방어력 speed INT 몬스터의 이동속도 color STRING 몬스터의 구분용 색 (헥사 색상 코드) { "name": "monster", "version": "1.0.0", "data": [ {"id":5001,"health":5,"defense":2,"speed":150,"color":"#FFFFFF"}, {"id":5002,"health":8,"defense":2,"speed":200,"color":"#E0E0E0"}, {"id":5003,"health":12,"defense":5,"speed":400,"color":"#C0C0C0"}, {"id":5004,"health":15,"defense":5,"speed":200,"color":"#A0A0A0"}, {"id":5005,"health":25,"defense":3,"speed":250,"color":"#808080"}, {"id":5006,"health":50,"defense":8,"speed":1000,"color":"#606060"}, {"id":5007,"health":100,"defense":15,"speed":300,"color":"#404040"} ] } -
DATA - Unlock
Field Type Description id INT unlock 조건의 고유 ID target_id INT 해금되는 아이템/몬스터의 ID stage_level INT 해금되는 스테이지 레벨 { "name": "unlock", "version": "1.0.0", "data": [ { "id": 101, "target_id": 1001, "stage_level": 1 }, { "id": 102, "target_id": 1002, "stage_level": 2 }, { "id": 103, "target_id": 1002, "stage_level": 4 }, { "id": 104, "target_id": 1002, "stage_level": 5 }, { "id": 105, "target_id": 1002, "stage_level": 7 }, { "id": 106, "target_id": 1002, "stage_level": 9 }, { "id": 107, "target_id": 5001, "stage_level": 1 }, { "id": 108, "target_id": 5002, "stage_level": 2 }, { "id": 109, "target_id": 5003, "stage_level": 4 }, { "id": 110, "target_id": 5004, "stage_level": 5 }, { "id": 111, "target_id": 5005, "stage_level": 7 }, { "id": 112, "target_id": 5006, "stage_level": 9 }, { "id": 113, "target_id": 5007, "stage_level": 10 }, ] }
세션 모델 구조 설계
- User
| Field | Type | Description |
|---|---|---|
| uuid | UUID | 유저의 고유 ID |
| nickname | STRING | 유저의 닉네임 |
| socketId | STRING | 웹소켓 ID |
| highScore | STRING | 유저의 최고 점수 |
| health | INT | 피격/회복될 시의 유저 체력 |
| damage | INT | 증가/감소될 시의 유저 공격력 |
| defense | INT | 증가/감소될 시의 유저 방어력 |
| speed | INT | 증가/감소될 시의 유저 이동속도 |
- Stage
| Field | Type | Description |
|---|---|---|
| userId | UUID | 유저의 고유 ID |
| currentStage | INT | 플레이어가 현재 진입한 스테이지 |
| score | INT | 플레이어의 이전 스테이지 클리어 점수 |
| timestamp | TIMESTAMP | currentStage로 진입한 시간 |
기본 파일 구조와 작동 방식 분석
- 이번 프로젝트의 기본적인 파일 구조다.
.
├── readme.md
├── assets // Data Table
│ ├── item.json
│ ├── monster.json
│ ├── unlock.json
│ └── stage.json
├── public // Front-End
└── src // Source code(=Server/Back-End)
├── app.js
├── constants.js // 게임 버전 관리용 상수
├── handlers
│ ├── game.handler.js
│ ├── handlerMapping.js
│ ├── helper.js
│ ├── register.handler.js
│ └── stage.handler.js
├── init // 필수 데이터, 기능 로드 (load)
│ ├── assets.js
│ └── socket.js
└── models // 세션 모델 관리
├── stage.model.js
└── user.model.js
- 설계한 내용을 바탕으로 구조를 그려보았다.
-
황색은 데이터의 전달 및 수정을 나타냄
-
적색은 실행 트리거를 나타냄
-
흑색은 논리적으로 이어져 있어 실행 시켜줄 수 있다는 의미