3. 실전 프로젝트란?
(게임식으로 말하자면)
NHN NEXT 이벤트(커리큘럼) 중
실제 기업으로부터 퀘스트(과제)를 받아 수행하며
학생의 레벨업을 도모합니다.
잠시 소개!
http://www.clipartbest.com/cliparts/LiK/qXg/LiKqXgzia.jpeg
용사를
잡아오세요!
6. 게임 기획
게임 목적
- 3개의 말을 튀겨서 목표 지점에 먼저 도달시키면 승리!
기본 조작
- 말을 터치 한 후 뒤로 당기면 화살표 생성
- 화살표의 방향이 말이 나아갈 방향을 표시
핵심 목표
- 말을 튀겨 목표 지점에 도착하도록 하는 것
7. 게임 기획
게임 방법
- 이동 가능한 코스를 타일 형태로 구성
- 코스를 벗어나는 경우 낙마 처리
- 낙마 된 말은 바로 직전의 리젠 위치에서 새로 시작
- 말과 말이 부딪히면 충돌 처리 되어 튕겨나감
- 상대의 말을 의도적으로 부딪혀서 튕겨나가게 할 수 있음
- 서로 번갈아가면서 턴 제로 진행
- 1턴에는 10초의 시간 제한이 있으며 해당 시간 내에
조작을 입력하지 않으면 타임 아웃으로 입력 없이 진행
- 1턴에 튀기는 회수는 단일 플레이어 기준 [1회 → 2회] 반복
8. 데모 영상
로그인, 친구 초대
슬라이드쉐어? - http://youtu.be/aWo__csz_Qw
9. 데모 영상
온라인 대전 플레이
슬라이드쉐어? - http://youtu.be/_inVFZCRE_E
11. 게임 엔진 선정
- 아티스트 부재(리소스를 구하기 힘듬)
3D가 아닌 2D로 만들자!
- Unity? Cocos2d-X?
유니티에 경험이 있으므로 바로 개발에 들어갈 수 있음
12. 서버 선정
- 요구 명세서의 필수 사항 : 플레이어간 view 동기화 필요
- WebServer? SocketServer?
- 클라이언트를 유니티로 정했으므로 서버는 C#으로 만들기로
13. WebServer vs SocketServer
반응성
만약 A플레이어가 입력을 한 순간 바로 B에게 영향을 주려면?
웹서버를 사용하게 되면 클라이언트가 계속 폴링해야함
롱폴링 등의 꼼수를 사용해도 플레이 지연이 불가피
모바일 환경
모바일 환경에서는 핸드오버가 발생(LTE ⇄ Wi-Fi,Wi-Fi ⇄ Wi-Fi)
웹 - 매번 요청 할 때 마다 새로 접속하므로 문제가 없음
소켓 - 소켓을 연결시켜 두므로 핸드오버에 대한 별도 처리가 필수
14. 핸드오버
ServerClient
1.로그인 요청
2.유저 세션 생성과 key발행
- 항상 소켓이 정상적으로 잘 작동하는지 확인 (HeartBeat)
- 문제가 발생하면 바로 새로운 소켓으로 재접속
- 단 기존 접속자임을 증명하기 위한 credential key가 필요(세션키)
16. GameRoom
ClientSession
!
- credential key
- socket
- playerData
ClientSession
!
- credential key
- socket
- playerData
ClientSession
!
- Same credential key
- new socket
- playerData
핸드오버
핸드오버로 재접속을 시도한 클라이언트 발생
동일한 credential key를 보유중
17. GameRoom
ClientSession
!
- credential key
- socket
- playerData
ClientSession
!
- Same credential key
- new socket
- playerData
ClientSession
!
- credential key
- socket
- playerData
핸드오버
새로 접속한 클라이언트로 교체
!
여기서 playerData가 깔끔하지 못하므로
뒤에 나올 리팩토링 이야기에서 다룰 예정
18. 핸드오버 기능을 적용한 C# 서버 프로토타입
( 개발 기간이 짧아 게임 기획이 나오기 전부터 서버 작업 )
19. 유니티와 C#서버 조합
유니티에서도 C#을 사용
C#으로 서버를 짜니 수정이 거의 필요 없음
동일 코드 사용 가능!
!
패킷 핸들러 관련은 동일 코드 사용
시뮬레이션 로직은 유니티에 종속적인 요소들이 추가
서버에 바로 적용이 힘들어짐
개발 기간 부족으로 인해 결국 서버의 역할 축소
28. 쉬운?? 리펙토링
ClientSession
!
- Same credential key
- new socket
- playerData
- 핸드오버 시 플레이어 데이터는 지속, 연결 정보는 교체 필요
- 연결 정보와 플레이어 정보의 분리
(다른곳과 결합된 곳이 없어 쉽게 분리)
32. Band 사용자 검증
Flask rest api server band server
Client
userKey, accessToken
band server
accessToken
밴드에서는 유저 고유키(공개)만으로 유저 판별
실제 그 유저가 본인인지 확인하기 위해 토큰 확인 필수
33. Band, Guest 가입
Flask rest api server band server
Client
UUID
band server
밴드로부터 로그인을 하면 밴드로부터 받은 userKey를 사용
만약 밴드 연동이 되어있지 않으면
UUID를 생성하여 userKey대용으로 사용
35. 끝없는 예외 시나리오
강제 접속 종료!
하나의 강력한 기준을 세우는 것이 중요
하지만 그래도 예외 상황이 많고 처리가 잘 안 되고 있음
36. try catch 쓰지 않기
아무리 C#이라 해도 개발 중에는 try catch를 사용하지 않고
문제 발생시 바로 브레이크를 걸거나 덤프를 떠서 문제 해결에 주력
!
그 상황을 모른척 넘긴다 해도 다른곳에서 문제를 또 일으킬 것이고
전혀 엉뚱한 곳에서 터지면 원인 파악에 방해만 될 뿐…
38. - 유니티의 물리 엔진은 FixedTime마다 연산을 처리
- 사실상 물리 처리가 실시간으로 이루어지므로
연산의 결과는 렌더링이 끝난 시점에서나 알 수 있음
- 미리 연산의 결과를 얻기 위해 직접 물리 로직을 구현하기로 함
물리 구현
39. - 코루틴을 프로그램의 흐름 분기 나누는 용도로 활용
- 그러다보니 마치 스레드인 것처럼 살짝 착각(…)
- 렌더링을 위한 Update() 내에서 물체의 이동을 코루틴으로 처리
- yield return new WaitForSeconds(0.01f); 을 100번 돌린다고
1초가 되지 않는 슬프고도 뼈아픈 현실 ㅠㅠ
- 결국 갈아엎음
코루틴은 멀티스레드가 아니란다
40. - 상태의 유지를 필요로 하는 오브젝트들에 대해서 FSM 구현
- 게임 턴 진행이나 말의 현재 상태 등이 적용 대상
- delegate로 필요한 state들을 미리 작성해두고 필요할 때 호출
delegate
41. - 비동기 작업 등 프로그램의 분기가 나뉘어 진행되나
멀티 스레드처럼 실시간 성이 필요 없을 때 사용
코루틴은 이런 용도로
42. 게임을 쉽게 플레이 할 수 있도록 1
진동 피드백
테스트 플레이로 얻은 피드백 中
!
- 말을 원하는 위치로 이동시키기 위해
어느 정도의 힘을 필요로 하는지 알 수 없다
43. 게임을 쉽게 플레이 할 수 있도록 1
진동 피드백
약한 진동 강한 진동
햅틱 라이브러리를 사용하여
플레이에 도움을 줌
!
진동 세기를 2단계로 분리
이동 거리가 길어지면
더욱 강한 진동이 발생
44. 게임을 쉽게 플레이 할 수 있도록 2
조준선
직접 구현한 물리 로직으로 플레이어 조작과 함께
미리 시뮬레이트 한 결과를 알 수 있음
그 결과 예상 도달 지점을 추측 가능하게 됨
45. 맵 에디터
자동 맵 생성을 포기하고 수동으로 맵 생성
기존 클라이언트를 복사해서 개조
46. 싱크 맞추기
- 부동 소수점 문제로 인해 오차가 조금씩 발생
- 오차 범위는 매우 적지만 티끌 모아 태산…
- 결국 전혀 다른 결과를 얻게 되므로 클라이언트 간 동기 필요
47. 싱크 맞추기
턴 메시지를 보여주면서 화면을 약간 반투명하게 만든 후
핀을 살짝 이동시키는 꼼수(?)를 사용하여 동기
53. 안드로이드 Custom URLScheme
별도의 안드로이드 activity를 만들어서 Intent-Filter에 등록
유니티에서 PlayerPrefs는 안드로이드의 SharedPreferences와 동일
안드로이드에서 SP로 저장하고 유니티에서 PP로 호출
54. 안드로이드 Custom URLScheme
← 일반적인
앱 실행시 호출
← URLScheme을
통한 호출
하지만 URLScheme 실행의 경우 MainLaunch 액티비티가 아닌
Scheme용 액티비티가 호출이 되어 밴드SDK용 액티비티 호출이 안됨
URLScheme용 액티비티에서 작업 완료 후 메인 액티비티를 강제 호출
55. 오작동 하는 주제에 프로그램이 죽지도 않아서 문제(…)
의심 가는 곳은 일일히 로그를 남겨가면서 확인 + 추리식 디버깅
안드로이드 디버깅 헬