슈퍼마리오 멀티플레이어 개발 후기

coolspeed

팀 합류 과제로 게임제작 미션을 받았다.

나는 과제로 “슈퍼마리오 멀티플레이어 게임”을 만들었다:

EnemyCD.gif

과제 결과물을 왓 스튜디오의 허락을 받고 소스코드를 Github 에 공개하였다:

https://github.com/coolspeed/MarioMultiplayer

관심 있으신 분들은 별표 하나씩 찍어 즐찾해주시길 부탁한다.

게임 룰: 위의 GIF 움짤  그대로. 먼저 상대방을 밟는 쪽이 이긴다.

과제가 1차, 2차로 나뉘는데 1차에서는 싱글 플레이어 슈퍼마리오를 만들었고 2차에서는 그것을 멀티플레이어 게임으로 발전시켰다.

최종 클라이언트 Java (Processing) 1500 줄, 서버 C# 22줄로 짜여졌다.

클라이언트

Processing 으로 만들었다. 왜?

    1. Processing 이 좋아서. (유쾌한 시각적 프로그래밍)
    1. Unity 쓸줄 몰라서.
    1. 다른 엔진도 쓸줄 몰라서.
    1. 엔진부분이 더 재밌어서.
  1. 웹에다 배포하고 싶어서. (P5.js 를 통하여. 하지만 망했다. 그냥 일반 Processing 애플리케이션처럼 exe 파일로 빌드했다.)

서버

단순한 릴레이 서버.

big_mirror.png

넷코드

ZeroMQ 를 네트워크 라이브러리로 사용했다.

처음에는 60 packets / s 로 나이브하게 시작했다.

60 fps 게임이니까 동기화 어긋날 일 없겠지 후훗.

그러다가 이런 질문을 하게 되었다:

꼭 매 프레임마다 동기화를 해야 할까?

자유낙하.png

마리오가 점프를 하면 확정된 궤적인 포물선을 따라 움직일게 뻔한데.

내 마리오가 <웨스트월드>처럼 대사를 해줬으면 좋았을텐데…

Dolores.png

최호영님이 NDC 에서 발표한 그래프 동기화잖아!

포물선 (그래프) 이 이미 전달됨.

곧바로 보다 흥미로운 질문에 빠졌다:

패킷을 과연 어디까지 줄일 수 있을까?

어렵지 않게 결론에 도달하게 된다 — 키보드 입력 횟수만큼.

(보다 정확한 서술은: 키보드 입력이 있는 프레임 수만큼.)

Donald Knuth 란 컴퓨터 과학자가 있는데 가장 빠른 알고리즘을 찾아낼 뿐만 아니라 그것보다 더 빠를 수 없음을 증명해내기까지 한다는 이야기가 미담으로 전해지고 있다.

전문용어로는 사실 “문제의 복잡도 하한선” 이라고 한다.

“입력횟수만큼만 동기화” 하려면 뭘 더 해야 할까? 많이 변경해야 했는데.

이렇게 얼기설기 얽혀있는걸 어떡해.

가시.png

디버깅을 어떻게 하지 하다가..

머리로 딱 시뮬레이션을 돌려봤을 때는

6usagmh.gif

debugging.gif

프로그래머가 길을 잃었을 때는

journey.jpg

검증되고 검증된 방법론을 찾게 되는 것 같다.

개인적으로 이 말을 굉장히 좋아한다:

사건이 발생한 원인은

사건이 발생한 계층에 있는 것이 아니라

그와 인접한 상위계층에 있다

Layered Architecture!

layer_architecture.jpg

많은 영역에서 검증됨:

    • 하드웨어
    • 소프트웨어
    • 통신
  • 포토샵

이렇게 하여 명료해졌다:

스크린샷 2017-04-11 오전 12.50.25.png

이런 궁극적 질문도 보다 쉽게 던져볼 수 있게 되었다:

신은 주사위를 던지는가?

이 게임에서는 신의 주사위가 끼어들 곳이 없음을 확인할 수 있다.

스크린샷 2017-04-11 오전 12.52.01.png

상태전달 플로우를 그려보자면:

스크린샷 2017-04-11 오전 12.50.25
스크린샷 2017-04-11 오전 12.52.58.png
스크린샷 2017-04-11 오전 12.53.09.png
스크린샷 2017-04-11 오전 12.53.17.png

스크린샷 2017-04-11 오전 12.53.30.png

스크린샷 2017-04-11 오전 12.53.44.png

상태 전달이 끝나면 상태를 통째로 굽고

스크린샷 2017-04-11 오전 12.53.56.png

그리고 네트워크에 탑재

스크린샷 2017-04-11 오전 12.54.12.png

그런 다음 렌더링 연출을

스크린샷 2017-04-11 오전 12.54.26.png

말로만 듣던

“유저 입력 -> 게임 로직 -> 렌더링” 순으로 처리해야

하는 원인을 몸소

#깨달음

그것은 엄연한 상태흐름의 순서였다.

통신을 줄였음을 자랑하기 위한 통신 시각화를 만들었다.

“패킷 인디케이터”라고 이름지었다.

패킷 최적화

Before:

60packets_per_second_color_shadowed_light.gif

After:

packet_indicator.gif

승부판정

h8bs5kxh.jpeg

진실은 오직 하나뿐이니까

—— <명탐정 코난>

#그런데 말입니다

우리는 과연 진실을 알 수 있을까?

800px-Speed_of_light_from_Earth_to_Moon.gif

움짤은 빛의 속도로 지구에서 달까지 가는데 걸리는 시간을 나타내는 움짤이다.

우리 눈에 보이는 달은 1.3초 전의 달이다.

오버워치 프로게이머 파인의 맥크리 영상:

파인_맥크리.gif

https://youtu.be/Xg-KPy3YKss?t=9m31s

(9분 31초부터)

앉았다 일어났다 하면서 맥크리로 상대방의 스나이퍼를 잡는 기염을 확인할 수 있다.

극한 상황에서 누구의 손을 들어줄 것인가?

FTS – Favouring The Shooter

오버워치 넷코드 핵심 원칙 중 하나라고 한다.

과제 하다가 넷코드에 관심이 많아져 막판에 본격적으로 공부했다.

리얼 월드 넷코드의 접근들과의 같은 점, 다른 점 연구. 그 결과 동기화 정책이 크게 아래와 같은 세가지로 나뉜다는 것을 알게 되었다:

    1. 결정론적 Lockstep (Deterministic Lockstep)
    1. 스냅샷 인터폴레이션 (Snapshot Interpolation)
  1. 상태 동기화 (State Synchronization)

공부한 결과 나의 방법이 3번 상태 동기화라는 것을 알게 되었다. 오버워치도 3번 상태 동기화라고 하더라.

images.jpg

내 방법이 교과서적인 방법이었다니…  역시 난 천재들이랑 똑같게 생각했어. 아니야 난 천재야!

url.jpg

내 방법이 교과서적인 방법이었다니… 바퀴를 재발명한 것 뿐이었어 ㅠㅠ

어쨌든 최종적으로 코드량은

    • 클라: Java 1500줄
  • 서버: C# 코드 22줄

로 과제를 구현했으며

#나무보다는 숲

을 보게 되었다. 그리고 그리하여

본질로 도달하게 되었다.

2.jpg

결론

뭐 그냥 그런 과제였다. 높은 기대감 갖고 코드를 읽으면 실망할 것이 분명하다.

어쩌다 싱글플레이어 게임 만들다가 멀티플레이어 게임으로 되어버렸다.

미션이라고 했지만 울며 겨자먹기로 한 것이 아니라, 업무시간에 월급받아가면서 게임제작 덕질을 한 것이다.

해명

  • Processing 은 Java 방언인데, 요즘 Processing 의 포지셔닝은  자칭 “플랫폼”으로 Javascript 모드인 P5.js 도 지원하고 Python 모드도 지원한다.
  • 메소드들이 다 public 인 원인은 Processing 에서 public 밖에 지원 안하는 줄 알고 그렇게 한거였다. 그리고 웬지 Processing 스타일대로 밖에서 다 public 으로 부를 속셈도 있었다. 페이크 private 메소드들이 언더바로 시작한 원인은 나름 이 “제한”속에서 “private” 약속을 해보기 위한거였다. 결과적으로 레거시 코드인데, 이걸 고칠까 고민중이다.
  • 소스코드에 레거시와 “과제”를 위한 “덕테이프”들이 다소 존재한다. 걸러서 읽으시길 추천한다.

다시 한번 Github 링크를:

https://github.com/coolspeed/MarioMultiplayer

관심있으신 분들 별표 찍어 즐찾 부탁해요~

References

    1. Developer Update: Let’s Talk Netcode – Overwatch: https://www.youtube.com/watch?v=vTH2ZPgYujQ
    1. Introduction to Networked Physics: http://gafferongames.com/networked-physics/introduction-to-networked-physics/
    1. Deterministic Lockstep: http://gafferongames.com/networked-physics/deterministic-lockstep/
    1. Snapshots and Interpolation: http://gafferongames.com/networked-physics/snapshots-and-interpolation/
  1. State synchronization: http://gafferongames.com/networked-physics/state-synchronization/

4 thoughts on “슈퍼마리오 멀티플레이어 개발 후기

Leave a reply to 김지환 Cancel reply