Realtime WebGame 개발

WebSocket을 응용하여 뱀파이어 서바이벌류 웹 게임에 서버를 연결하여 스테이지 관리 아이템 시스템을 구현해보려 한다!

구현 목표

  1. 스테이지의 구분

    • 클라이언트의 일정 점수/시간이 지나면 서버에 요청하여 스테이지가 달라져야 함
  2. 스테이지에 따른 점수 획득 구분

    • 스테이지가 올라갈수록 획득하는 점수가 달라져야함
  3. 스테이지에 따라 아이템 생성

    • 아이템이 스테이지 정보에 따라 생성될 수 있게 설계
  4. 아이템 획득 시 점수 획득

    • 아이템 획득 시 서버의 검증 뒤에 획득

    • 추가로 아이템 생성 시간을 이용하여 어뷰징 행위 방지 기능

  5. 아이템 별 획득 점수 구분

    • 아이템에 따라 획득하는 점수가 달라야 하며, 이를 서버에서 검증해주어야 함
      (획득 점수, 획득 스테이지)
  6. Broadcast 기능 추가

    • 모든 유저에게 알릴 수 있는 기능 추가하기 (실시간 채팅?서버 알림?)
  7. 가장 높은 점수 Record 관리

    • 가장 높은 점수는 현재 클라이언트에서 저장되고 있으나, 이를 서버에서 관리하는 형태로 수정

    • 서버에서 가장 높은 점수가 갱신되면 현재 게임에 참여한 유저들에게도 알려주어야 함

  8. 유저 정보 연결

    • 유저 ID를 클라이언트가 알고 있다면, 다음 접속부터 이전 게임 기록에 연동이 가능하여야 함

      => 로그인/회원가입 기능?

  9. 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
  • 설계한 내용을 바탕으로 구조를 그려보았다.

설계도 drawio

  • 황색은 데이터의 전달 및 수정을 나타냄

  • 적색은 실행 트리거를 나타냄

  • 흑색은 논리적으로 이어져 있어 실행 시켜줄 수 있다는 의미