유니티 네트워크 게임 프로젝트

2017. 10. 19. 15:02기술/유니티 스터디

반응형

프로젝트명 : 유니티 파이터즈


기획 및 프로그래밍 : 송현국


목표 : 유니티 에셋 스토어에서 무료 모델들을 사용하여 빠르게 게임 프로젝트를 하나 완성한다.


사용 엔진 : 유니티 3D엔진, 프라우드넷 서버엔진


게임 장르 : 네트워크 대전


 1인개발을 지향하는 것은 절대 아니고 당연히 프로젝트 규모에 맞는 인원수가 필요합니다. 이 프로젝트는 연구 및 포트폴리오용입니다.


그럼 시작하도록 하겠습니다.


 첫번째로 맵을 만들어야 하는데 그냥 밑판(Plane)하나 깔고 이것을 맵이라~ 라고 해도 괜찮지만 조금 더 성의를 보여서 맵 에셋을 다운로드 받아보도록 하겠습니다. 상용화 수준으로 보일려면 아래와 같은 맵을 사용해야 겠지만 지금 제가 개발할 때 속도가 나지 않으므로 다른 맵 에셋을 사용하도록 하겠습니다.


희망사항 맵 퀄리티 (2017 유니티 에셋 어워드에 선정된 완성된 프로젝트인데 정말 완성도가 좋습니다.)


프로토타입 게임 프로젝트에는 이정도도 무난합니다.


이렇게 맵 하나와 캐릭터 2명을 준비하고 캐릭터를 맵에 배치합니다.


그리고 유니티에서 폴더 구성을 해줍니다. 저는 GameDesigner, GraphicDesigner, Programmer 이렇게 세 폴더로 나누고 Characters 밑에 Player와 Monster로 구분하였습니다.


맵, 카메라를 조금 이동시켜서 알맞은 위치를 만들어주고 프로그래머가 사용할 프리팹은 다운로드 받은 에셋의 프리팹을 복제(Duplicate, Ctrl + D)하여 사용하도록 합니다. 그렇게 해야 원본이 남아있는 상태에서 해당 프리팹을 사용할 수 있습니다.


또한 다른 기능을 사용해야 하므로 복제된 프리팹에서 불필요한 컴포넌트만 제거(Remove)합니다. 주로 Animator 관련된 컴포넌트들이 달려있습니다.


아래에 머리카락이나 옷에 조인트(Joint)를 달아주면 물리효과에 의해 움직이는 것을 구현할 수 있습니다. 인게임에서 이 물리효과를 적용할지 여부를 성능 옵션에서 선택할 수 있도록 하면 조금 더 쾌적한 전투를 할 수 있겠습니다.


관련 설명 블로그 링크1, 링크2

저는 네트워크 플레이를 중점적으로 구현할 생각이기 때문에 이 기능에 대해 시간이 되면 더 알아보도록 하겠습니다.


그리고 저 계층구조(Hierarchy)에서 Hair_Grp의 메쉬를 바꿔주면 머리카락을 바꿀 수 있습니다. 음.. 초기에 애니메이터가 애니메이션을 잡을 때 신경써 주어야 할 것 같습니다.


일단 모바일에서 간략화 해서 본다면 머리, 상의, 하의, 손, 발정도면 될 것 같습니다.

복잡하게 한다면 나머지는 악세서리로 얼굴(안경등), 등(가방 날개등), 허리(밸트) 정도가 되겠습니다.



그리고 참고하기 위해 에셋 스토어에서 3D 예제 프로젝트 Survival Shooter를 추가(Import)합니다.


1. 캐릭터 조작(Control)

 첫번째로 할 것은 무엇인가? 캐릭터 애니메이션 보다 일단은 캐릭터 조작에 관하여 구현해 보도록 하겠습니다. 그 중 이동에 관한 것입니다. 일단 유니티에서는 Character Controller라는 것이 있는데 물리적 효과를 적용하려면 Rigidbody를 사용하라고 메뉴얼에서 설명해 주고 있습니다.

 저는 Survival Shooter에 있는 Capsule Collider와 Rigidbody 컴포넌트들을 추가하도록 하겠습니다. 그리고 PlayerControl.cs이라는 컴포넌트 스크립트를 하나 생성하겠습니다.



 유니티는 게임 오브젝트 컴포넌트 시스템(GameObject Component System)으로 설계되어 있습니다. 상속 관계가 복잡해 질 수 있는 상황을 해결하기 위해서 여러가지 구성요소를 조합해서 만드는 설계방식입니다. GPG 6권에 소개되어있습니다.


 캐릭터 프리팹을 다른 씬에 추가하면 바로 사용할 수 있도록 독립적인 객체로 설계하고 구현할 예정입니다. 싱글턴 패턴같은 설계를 잘못 적용하다 보면 캐릭터만 따로 분리해 내기 힘든 경우가 있는데 그러한 상황을 만들지 않게 할 것입니다.


Rigidbody는 물리효과를 적용하도록 해주는 구성요소(Component)입니다.

Capsule Collider는 충돌을 탐지하는 역할을 하는 구성요소입니다.

CharacterControl은 캐릭터 조작에 관한 역할을 하는 구성요소입니다.


 현재 이 캐릭터는 Transform 구성요소를 포함하여 총 4개로 구성되어 있는 게임오브젝트 입니다.


2. 캐릭터의 이동(Move)


Survival Shooter 튜토리얼을 참고하여 이동을 만듭니다.

다음과 같이 되어 있는데 추후 모바일에서 사용하기 위해서는 별도의 컨트롤러 UI가 필요합니다.


Vector3 m_vecDirction은 방향벡터입니다. 벡터의 개념에 대해서 알아야 합니다. 벡터는 그래픽스 이론에서 가장 기본이 되는 방향과 크기가 있는 하나의 값 입니다. 어떤 수치에 어떻게 방향을 나타낼 수 있을까? 벡터를 사용하면 됩니다.

그러니까 3차원 공간(x, y, z)에서 기준 위치를 (0, 0, 0) 으로 두고 벡터 값이 (1, 1, 1)이면 이것을 그려보면 벡터를 알 수 있습니다.


코드에서 캐릭터를 어떻게 움직이는가~

일단 방향벡터(m_vecDirection)를 설정해주고 방향 벡터에 m_fSpeed 스칼라 값을 곱해 준 다음 프레임 당 일정한 속도로 움직이게 하기 위해 Time.deltaTime을 곱해줍니다.

이 값을 m_vecMoving에 대입해서 값을 가지고 있습니다.


그리고 m_rigidBody를 통해서 해당 위치로 이동을 시켜주게 됩니다. 여기에서 기준 위치는 (0, 0, 0)이 아니라 현재 위치 transform.position 이며 이동할 위치가 위에서 계산된 m_vecMoving입니다.


이 m_fSpeed가 계속 개발하다 보면 나중에 복잡해질 수 있습니다. 

이속 증가 아이템 사용시, 상대 스킬에 맞아서 이속 감소가 될 수도 있고 아군한테 버프를 받아서 이속이 빨라질 수도 있습니다.


보통 아이템 착용 관련된 스텟들은 이미 캐릭터 정보에서 전부 계산이 되어 있기 때문에 초기 변수에 바로 대입해줄 수 있습니다.

상대방 스킬에 맞아서 이속이 감소될 경우는 따로 변수를 두어야 할 것입니다.

다음 아군에게 버프를 받거나 몬스터 사냥시 이속이 빨라진다던가 하는 것들도 따로 변수를 두어서 처리할 수 있겠습니다.

그리고 탈것을 타고 내릴 때도 이동속도가 변할 수 있겠습니다.


총 공식은 m_fSpeed = m_fItem + m_fDownSpdSkill + m_fUpBuffSkill + m_fKillMon + m_fRide ...


RPG에서 다른 스텟들도 이렇게 공식이 복잡해질 수 있습니다. 하지만 이것이 RPG의 묘미라고 생각하고 이런 능력치들을 올리기 위해 좋은 아이템을 얻는다고 생각합니다.


CharacterControl.cs (이 코드는 개발중 수정될 수 있습니다.)



3. 네트워크 P2P통신

 통신을 준비하기 위해서 필요한 것은

 클라이언트

 1. 프라우드넷 유니티 라이브러리

 2. Network 이름의 GameObject와 Network.cs 컴포넌트 스크립트 파일

 3. NetClient 프라우드넷 객체

 4. Marshaler.cs PIDL 형변환 스크립트 파일


 서버

 1. 프로젝트 환경설정, 프라우드넷 Win32 라이브러리

 2. PIDL 파일과 빌드 후 나온 Proxy, Stub파일

 3. CNetServer 프라우드넷 객체


프라우드넷의 유니티 플러그인을 복사해 옵니다.



구성 속성입니다. 사용자 지정 빌드 도구


명령줄

.\PIDL\pidl.exe %(Fullpath)

.\PIDL\pidl.exe -cs %(Fullpath) -outdir E:\Development\Projects\Unity5\StudyNetwork\Assets\Scripts\PIDL\

설명

Compiling %(Fullpath)...

출력

%(directory)\PIDL\(filename)_proxy.h

추가 종속성

.\PIDL\pidl.exe


 음.. 로그인을 했을 때 캐릭터가 추가 되어야 하는등 생각하고 구현해야 할 것이 조금 있습니다. 시간이 조금 걸릴것 같은데 일단 로그인 하고 다른 캐릭터가 맵에 추가되는 것이 보여야 합니다. 이것을 구현하기 위해서는 서버에서 로그인한 유저들을 모두 CFastMap에 가지고 있어야 합니다. 그리고 새로 로그인 한 유저에게 기존에 로그인 했던 유저들을 알려서(Notify) 기존 유저들을 맵에 보여주어야 합니다. 기존 유저들은 새로 로그인 한 유저의 캐릭터를 볼 수 있어야겠죠.


 그 다음 서버에도 능력치(Stat) 정보를 가지고 있어야 합니다. 그 이유는 서버와 접속이 끊어졌고 다시 접속했을 때 다른 유저들의 캐릭터 정보를 다시 보내주어야 하기 때문입니다.


4. MORPG, MMORPG 또는 AOS 방식?

 연구중에 이 두 가지 방식중 어느 방식을 선택해야 하는지 생각해야 했습니다. MORPG는 적은 인원이 함께 던전을 돌 수 있는 게임 방식이고 MMORPG는 특정 지역에서 많은 인원이 게임을 함께 즐기는 방식입니다. 서버와 클라이언트 설계 자체가 달라질 수 있으므로 둘 중 한가지 방식을 선택해야 합니다.


 요즘은 AOS 방식의 게임도 인기가 상당하지만 이 다음 세대의 게임 방식에 대해서 생각해보아야 합니다.


 1. 많은 유저들이 게임에 접속한다. (RequestLogin, ResponseLogin)

 2. 캐릭터를 생성한다. (RequestCreateCharacter, ResponseCreateCharacter)

 3. 5 VS 5 대전을 신청한다. (RequestBattle, ResponseBattle) 여기에서 10명의 정보를 모두 보내준다.

 4. 게임 시작

 5. 내 캐릭터를 컨트롤 하고 다른 유저의 동작 정보는 통보(Notify) 받는다.


 이 방식을 정하는 것이 중요한 이유

 MORPG 방식에서는 4명에서 한 스테이지에 들어가서 스테이지를 클리어한다고 했을 때, 도중 인터넷이 끊긴다든가 게임을 종료 해 버리면 다시 그 스테이지에 들어갈 수 없습니다. 이는 이 게임방식에서는 P2P 방식으로 통신을 해도 상관이 없다라는 이야기입니다. 하지만 MMORPG나 AOS 방식에서는 서버로 캐릭터의 이동 벡터 정보를 보내야 합니다. 그 이유는 새로 다른 유저가 접속 했을 때 기존 유저들 캐릭터의 이동 벡터 정보를 보내주어야 하기 때문입니다.


 


일단은 첫번째로 서버에 접속하는 사람이 전장을 만들고 두번째 부터 서버에 접속하는 유저가 그 전장에 추가되는 방식으로 만들었습니다.


캐릭터 이동시 UDP로 위치 벡터 값을 클라이언트에 보내고 다른 클라이언트에서 받아서 해당 캐릭터를 움직입니다.


- 캐릭터 상태 기계 구현 -

공격 메시지를 전달하기 전에 캐릭터 상태 기계 부터 구현을 해야 합니다. 

실제로 switch, if~else 문을 사용하여 일단 만들어 둔 다음 상태 패턴(State Pattern)을 사용하여 switch, if~else 문을 삭제하고 설계를 정리 하였습니다.


외에도 설계 수정, 코드 정리, 완성도 향상중에 있습니다.

기획자 전용 폴더 생성, 캐릭터 툴(Scene) 생성, 팩토리 패턴 사용등.



 기획자도 확인할 수 있도록 캐릭터 툴을 만들어 두었습니다. 추후 아이템 착용이라든가 임의 캐릭터 생성등이 가능하게 할 수 있겠습니다.


 위 동영상에서는 캐릭터 상태 기계 변환에 대해서 확인할 수 있습니다. 공격 메시지는 P2P TCP 로 보내주며 피격시 데미지 계산을 해주었습니다.


 상대방 캐릭터 이동시 내 화면에서도 달리기 애니메이션이 적용되어야 하는 부분 수정해야 합니다. 

 유니티 Rigidbody의 Velocity로 하면 편한데 이 값으로 할 경우 네트워크에서 정확한 위치값을 알 수 없으므로 다른 방법을 생각해 봐야 합니다.

 이 부분이 조금 복잡합니다. (링크) 이유는 기본 동작 상태에 있을 때에도 계속 패킷을 보내주는건 서버 과부화가 걸릴 수 있으므로 필요시에만 패킷을 보내게 최적화 해주어야 한다는 점에서 그렇습니다.


 네트워크 상태로 상대방이 공격하는 애니메이션은 잘 적용되는것을 확인할 수 있습니다.


 피격시 데미지 계산은 피격했다라는 메시지가 전달 될 때 처리됩니다.

 

 피격 구현은 첫번째 공격자와 피격자의 거리와 범위내 각도로 구현하는 방법과 두번째 충돌박스를 이용한 방법이 있습니다. 일단은 두번째 방법을 사용했습니다.


 카메라가 내 캐릭터를 따라다니도록 하였습니다.


 완성도 향상 후에 동영상 다시 업로드 하도록 하겠습니다.


2018-06-06 수정된 내용 (소요시간 6시간 30분)

  1. 패킷 송신을 1회로 하여 캐릭터 기본동작(Idle)과 달리기(Running) 상태 동기화

  2. 위치 동기화 하여 캐릭터가 목표지점으로 이동

  3. 카메라가 접속한 내 캐릭터를 따라다님



다음으로는 코드에 주석을 조금 더 달고 약간의 설계 수정과 코드 정리를 해야겠습니다.


반응형

'기술 > 유니티 스터디' 카테고리의 다른 글

유니티 최적화 링크  (0) 2021.06.03
유니티 빌드 시  (0) 2020.02.03
유니티에서 앱 다국어 이름 설정하기  (0) 2017.07.27
유니티 자체 안드로이드 플러그인  (0) 2017.02.18
UGUI  (0) 2017.02.14