[nhn next]실전프로젝트 밴드 게임 만들기 후기
TRANSCRIPT
NHN NEXT 실전 프로젝트
네이버 밴드 API를 활용한 게임 만들기
김덕철, 정문철V1.0
Warning!
실전 프로젝트 최종 발표 때 사용된 자료로써 슬라이드 쉐어 같은 공간에서는 전달이 미흡한 부분이 있을 수 있습니다.
실전 프로젝트란?
(게임식으로 말하자면) NHN NEXT 이벤트(커리큘럼) 중
실제 기업으로부터 퀘스트(과제)를 받아 수행하며 학생의 레벨업을 도모합니다.
잠시 소개!
http://www.clipartbest.com/cliparts/LiK/qXg/LiKqXgzia.jpeg
용사를 잡아오세요!
SprinteR
게임 제목(가제)
게임 기획
게임 기획
게임 목적 - 3개의 말을 튀겨서 목표 지점에 먼저 도달시키면 승리! 기본 조작 - 말을 터치 한 후 뒤로 당기면 화살표 생성 - 화살표의 방향이 말이 나아갈 방향을 표시 핵심 목표 - 말을 튀겨 목표 지점에 도착하도록 하는 것
게임 기획
게임 방법 - 이동 가능한 코스를 타일 형태로 구성 - 코스를 벗어나는 경우 낙마 처리 - 낙마 된 말은 바로 직전의 리젠 위치에서 새로 시작 - 말과 말이 부딪히면 충돌 처리 되어 튕겨나감 - 상대의 말을 의도적으로 부딪혀서 튕겨나가게 할 수 있음 - 서로 번갈아가면서 턴 제로 진행 - 1턴에는 10초의 시간 제한이 있으며 해당 시간 내에조작을 입력하지 않으면 타임 아웃으로 입력 없이 진행
- 1턴에 튀기는 회수는 단일 플레이어 기준 [1회 → 2회] 반복
http://bit.ly/1wsH2hU
데모 다운로드
- 네이버 밴드 설치 필수 - 알려지지 않은 출처 설치 옵션 활성화
12월 30일 이후 예고없이 서버가 삭제될 수 있습니다.
게임 엔진 선정
- 아티스트 부재(리소스를 구하기 힘듬) 3D가 아닌 2D로 만들자!
- Unity? Cocos2d-X?유니티에 경험이 있으므로 바로 개발에 들어갈 수 있음
서버 선정
- 요구 명세서의 필수 사항 : 플레이어간 view 동기화 필요 - WebServer? SocketServer? - 클라이언트를 유니티로 정했으므로 서버는 C#으로 만들기로
WebServer vs SocketServer
반응성만약 A플레이어가 입력을 한 순간 바로 B에게 영향을 주려면? 웹서버를 사용하게 되면 클라이언트가 계속 폴링해야함 롱폴링 등의 꼼수를 사용해도 플레이 지연이 불가피
모바일 환경
모바일 환경에서는 핸드오버가 발생(LTE ⇄ Wi-Fi, Wi-Fi ⇄ Wi-Fi)웹 - 매번 요청 할 때 마다 새로 접속하므로 문제가 없음 소켓 - 소켓을 연결시켜 두므로 핸드오버에 대한 별도 처리가 필수
핸드오버
ServerClient
1.로그인 요청
2.유저 세션 생성과 key발행
- 항상 소켓이 정상적으로 잘 작동하는지 확인 (HeartBeat) - 문제가 발생하면 바로 새로운 소켓으로 재접속 - 단 기존 접속자임을 증명하기 위한 credential key가 필요(세션키)
GameRoom
ClientSession !
- credential key - socket
- playerData
ClientSession !
- credential key - socket
- playerData
핸드오버
GameRoom
ClientSession !
- credential key - socket
- playerData
ClientSession !
- credential key - socket
- playerData
ClientSession !
- Same credential key - new socket - playerData
핸드오버
핸드오버로 재접속을 시도한 클라이언트 발생 동일한 credential key를 보유중
GameRoom
ClientSession !
- credential key - socket
- playerData
ClientSession !
- Same credential key - new socket - playerData
ClientSession !
- credential key - socket
- playerData
핸드오버
새로 접속한 클라이언트로 교체 !여기서 playerData가 깔끔하지 못하므로 뒤에 나올 리팩토링 이야기에서 다룰 예정
핸드오버 기능을 적용한 C# 서버 프로토타입 ( 개발 기간이 짧아 게임 기획이 나오기 전부터 서버 작업 )
유니티와 C#서버 조합
유니티에서도 C#을 사용C#으로 서버를 짜니 수정이 거의 필요 없음
동일 코드 사용 가능! !
패킷 핸들러 관련은 동일 코드 사용
시뮬레이션 로직은 유니티에 종속적인 요소들이 추가 서버에 바로 적용이 힘들어짐
개발 기간 부족으로 인해 결국 서버의 역할 축소
지난 학기 C++ 서버에서의 반성…
모든 게임로직을 서버에서 처리하기에 구조적으로 복잡
!커플링 문제가 심각
GameRoom !
- Player* …
Player !
- GameRoom*
커플링
Player !
- GameRoom*
편리함의 불안함
- delete가 없는 환경에서의 불안함… - GC가 잘 작동 되도록 모든 인스턴스를 한 곳에서 별도 관리 - 관리 인스턴스 호출 횟수 증가
GameRoom !
- (int)RoomNum - (int)PlayerNum…
Player !
- (int)RoomNum - (int)PlayerNum
Player !
- (int)RoomNum - (int)PlayerNum
참조 없애기
GameRoom !
- (int)RoomNum - (int)PlayerNum…
Player !
- (int)RoomNum - (int)PlayerNum
참조 없애기
g_RoomManager !
Map<(int)RoomNum, GameRoom*> …
g_PlayerManager !
Map<(int)PlayerNum, Player*> …
쉬운 GC
g_RoomManager !
Map<(int)RoomNum, GameRoom*> …
http://www.villageofschillerpark.com/assets/1/news/Garbage_Collection.jpg
GameRoom !
- (int)RoomNum - (int)PlayerNum…
refCount 0
쉬운?? 리펙토링
ClientSession !
- Same credential key - new socket - playerData
- 핸드오버 시 플레이어 데이터는 지속, 연결 정보는 교체 필요 - 연결 정보와 플레이어 정보의 분리
(다른곳과 결합된 곳이 없어 쉽게 분리)
MySql
C# GameServerFlask rest api
Client
가입, 랭킹 조회
게임 결과 업데이트
서버 혼용
api test
api 테스트는 크롬 확장도구인 Postman을 사용 테스트 케이스를 별도 파일로 저장 후 팀원간 공유
StoredProcedure적극 활용
거의 모든 쿼리를 다 SP로 만들어 사용
Band 사용자 검증
Flask rest api server band server
Client
userKey, accessToken
band server
accessToken
밴드에서는 유저 고유키(공개)만으로 유저 판별 실제 그 유저가 본인인지 확인하기 위해 토큰 확인 필수
Band, Guest 가입
Flask rest api server band server
Client
UUID
band server
밴드로부터 로그인을 하면 밴드로부터 받은 userKey를 사용 만약 밴드 연동이 되어있지 않으면
UUID를 생성하여 userKey대용으로 사용
끝없는 예외 시나리오
끝없는 예외 시나리오
강제 접속 종료!
하나의 강력한 기준을 세우는 것이 중요 하지만 그래도 예외 상황이 많고 처리가 잘 안 되고 있음
try catch 쓰지 않기
아무리 C#이라 해도 개발 중에는 try catch를 사용하지 않고 문제 발생시 바로 브레이크를 걸거나 덤프를 떠서 문제 해결에 주력 !그 상황을 모른척 넘긴다 해도 다른곳에서 문제를 또 일으킬 것이고 전혀 엉뚱한 곳에서 터지면 원인 파악에 방해만 될 뿐…
Client
- 유니티의 물리 엔진은 FixedTime마다 연산을 처리 - 사실상 물리 처리가 실시간으로 이루어지므로연산의 결과는 렌더링이 끝난 시점에서나 알 수 있음
- 미리 연산의 결과를 얻기 위해 직접 물리 로직을 구현하기로 함
물리 구현
- 코루틴을 프로그램의 흐름 분기 나누는 용도로 활용 - 그러다보니 마치 스레드인 것처럼 살짝 착각(…) - 렌더링을 위한 Update() 내에서 물체의 이동을 코루틴으로 처리 - yield return new WaitForSeconds(0.01f); 을 100번 돌린다고
1초가 되지 않는 슬프고도 뼈아픈 현실 ㅠㅠ - 결국 갈아엎음
코루틴은 멀티스레드가 아니란다
- 상태의 유지를 필요로 하는 오브젝트들에 대해서 FSM 구현 - 게임 턴 진행이나 말의 현재 상태 등이 적용 대상 - delegate로 필요한 state들을 미리 작성해두고 필요할 때 호출
delegate
- 비동기 작업 등 프로그램의 분기가 나뉘어 진행되나멀티 스레드처럼 실시간 성이 필요 없을 때 사용
코루틴은 이런 용도로
게임을 쉽게 플레이 할 수 있도록 1 진동 피드백
테스트 플레이로 얻은 피드백 中 !
- 말을 원하는 위치로 이동시키기 위해어느 정도의 힘을 필요로 하는지 알 수 없다
게임을 쉽게 플레이 할 수 있도록 1 진동 피드백
약한 진동 강한 진동
햅틱 라이브러리를 사용하여 플레이에 도움을 줌 !진동 세기를 2단계로 분리 이동 거리가 길어지면더욱 강한 진동이 발생
게임을 쉽게 플레이 할 수 있도록 2 조준선
직접 구현한 물리 로직으로 플레이어 조작과 함께미리 시뮬레이트 한 결과를 알 수 있음
그 결과 예상 도달 지점을 추측 가능하게 됨
맵 에디터
자동 맵 생성을 포기하고 수동으로 맵 생성 기존 클라이언트를 복사해서 개조
싱크 맞추기
- 부동 소수점 문제로 인해 오차가 조금씩 발생 - 오차 범위는 매우 적지만 티끌 모아 태산… - 결국 전혀 다른 결과를 얻게 되므로 클라이언트 간 동기 필요
싱크 맞추기
턴 메시지를 보여주면서 화면을 약간 반투명하게 만든 후 핀을 살짝 이동시키는 꼼수(?)를 사용하여 동기
길찾기 알고리즘 변화
AI
길찾기 알고리즘 조사
http://qiao.github.io/PathFinding.js/visual/
PathFinding.js로 적합한 알고리즘 조사하지만 벽에 붙어서 다니는것이 어색
길찾기 알고리즘 선정
맵을 수동으로 제작하면서 이동 경로를 수동으로 지정 맵에 정의 된 노드 기반으로 길찾기 개발
- 미리 시뮬레이션을 돌려 공격 가능한 범위 검출 - 공격 결과가 유효한지에 대해서 예측 후 행동 - 이동 경로가 설립 될 경우 해당 경로의 안전성 검증
AI Logic
안드로이드 Custom URLScheme
밴드 게임 초대 메시지는 해당 게임의 URLScheme를 실행 시켜주는 형태
안드로이드 Custom URLScheme
별도의 안드로이드 activity를 만들어서 Intent-Filter에 등록 유니티에서 PlayerPrefs는 안드로이드의 SharedPreferences와 동일
안드로이드에서 SP로 저장하고 유니티에서 PP로 호출
안드로이드 Custom URLScheme
← 일반적인 앱 실행시 호출
← URLScheme을 통한 호출
하지만 URLScheme 실행의 경우 MainLaunch 액티비티가 아닌 Scheme용 액티비티가 호출이 되어 밴드SDK용 액티비티 호출이 안됨 URLScheme용 액티비티에서 작업 완료 후 메인 액티비티를 강제 호출
오작동 하는 주제에 프로그램이 죽지도 않아서 문제(…) 의심 가는 곳은 일일히 로그를 남겨가면서 확인 + 추리식 디버깅
안드로이드 디버깅 헬
GlobalExceptionHandling
ErrorReport
ErrorReport
Async Await
서버측 비동기 작업에 사용 ( static, error report, log ) 써보니 굉장히 편리 - 비동기 작업의 끝판왕(by sm9) 하지만 서버에 올리니 크래시 → (원인) .NET 프레임워크 4.5 필요
자랑
- 딱히… - 이것저것 해본 것은 많음 template<잡케>
(TCP 게임서버, Flask 웹서버, Unity Client, 물리 엔진 제작, Band SDK 연동, 안드로이드, …)
- 딱히… - 이것저것 해본 것은 많음 template<잡케>
(TCP 게임서버, Flask 웹서버, Unity Client, 물리 엔진 제작, Band SDK 연동, 안드로이드, …)
좋게 말하
면 풀스택?!!
- 딱히… - 이것저것 해본 것은 많음 template<잡케>
(TCP 게임서버, Flask 웹서버, Unity Client, 물리 엔진 제작, Band SDK 연동, 안드로이드, …)
반성
친구의 가입 여부 조회를 위해 서버의 가입자 DB에서 친구가 등록되어있는지
확인하는 로직을 만들었으나… !
Band로부터 친구 목록을 가져올 때 이미 가입여부를 가져올 수 있었음…
API 가이드 문서 숙지
예전 프로젝트(3인)에서는 이슈 트레커를 활발히 사용 2인 체제에서는 바로 옆자리에 물어보면서 개발
협업툴 활용 저조
전체 개발기간 8주 중에서감기가 걸리니 2주가 증발
건강 관리를 잘 하자
감사합니다.