반응형

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번에는 함께 일하는 다른 팀원들에게 에셋을 전달하기 위해서 사용되는 유니티 패키지에 대해서 알아봅시다.

 

사용 엔진 버전 : 2020.3

 

타임라인

0:00 인트로

0:11 압축파일 전달

1:15 유니티 패키지

2:45 버전 관리 도구로써는? 글쎄...

3:41 유니티 패키지 사용법

4:59 아웃트로

 

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번 영상에서는 유니티에서 에셋을 전달하기 위해서 사용되는 유니티 패키지에 대해서 알아보도록 하겠습니다.

압축파일 전달

유니티에 익숙하지 못한 입문자일 때는 프로젝트나 프로젝트 안에 있는 텍스처, 머티리얼, 프리팹, 스크립트 같은 에셋을 공유하거나 전달하려고 프로젝트 전체를 압축해서 보내거나 전달할 에셋을 선택하여 압축해서 보내는 방법을 주로 사용했었습니다.

저도 유니티를 처음 배웠을 때는 그렇게 많이 했었죠.

하지만 이 방법을 사용하면 굉장히 많은 문제가 발생합니다.

전체 프로젝트를 압축해서 옮기면 프로젝트의 크기에 따라서 압축 파일의 용량이 너무 커져서 옮기기가 어려워 집니다.

물론 프로젝트에 필요한 폴더만 묶어서 압축하면 훨씬 압축파일의 용량이 줄어들지만, 이렇게 옮기면 프로젝트를 받은 사람이 처음 열 때 시간이 많이 걸린다는 단점도 있습니다.

그리고 압축 파일 이름에 버전을 적어둬도 어떤 게 어떤 버전인지 헷갈리는 문제도 발생합니다.

거기에 가장 치명적인 단점으로는 수동으로 파일을 선택할 때는 프리팹이나 씬에 포함된 오브젝트의 참조 관계, 즉 어떤 프로퍼티에 어떤 프리팹이나 텍스처 등의 에셋들이 꽂혀있는지 전부 알 수 없기 때문에 빠지는 파일이 생길 수 있습니다.

그렇게 되면 전달된 에셋들이 제대로 동작하지 않는 문제가 발생하게 됩니다.

유니티 패키지

앞에서 말한 압축 파일로 에셋을 전달하는 방법에서 발생하는 문제를 해결할 수 있는게 바로 유니티 패키지입니다.

먼저 유니티 패키지를 만드는 방법부터 보여드리겠습니다.

유니티 에디터의 프로젝트 뷰에서 유니티 패키지로 익스포트할 에셋을 선택합니다.

그 에셋에 우클릭하고 [Export Package]를 선택합니다.

그러면 Exporting Package 창이 뜨면서 선택한 에셋과 연관된 에셋, 즉 종속성을 가진 에셋들이 함께 자동으로 선택됩니다.

물론 프로젝트 크기가 커지면 이 종속성이 상당히 복잡해서 정말 필요한 에셋 뿐만 아니라 곁다리 수준으로만 엮인 에셋들도 선택되서 쓸데없는 에셋들이 함께 익스포트되는 경우도 있기 때문에 잘 확인하고 꼭 익스포트할 에셋들만 선택해야 합니다.

그리고 창에서 Include dependency 체크를 해제하면 정말 선택한 에셋만 잡히는데 지금 선택한 프리팹의 경우에는 필요한 3D 모델, 애니메이터 컨트롤러 등이 모두 빠지기 때문에 빈 오브젝트만 익스포트됩니다.

그래서 이 Include dependency 옵션은 보통은 정말 필요한 리소스 에셋이나 스크립트 에셋만 빼내야 할 때 체크를 해제해주면 됩니다.

이렇게 익스포트할 에셋을 모두 선택한 다음에는 Export 버튼을 누르고 저장하고자 하는 위치에 이 패키지가 무엇을 담고 있는지 확실하게 알 수 있는 이름으로 저장해주면 됩니다.

그리고나서 이 유니티 패키지를 임포트할 프로젝트를 실행하고 패키지 파일을 더블클릭해주면 패키지 안에 담긴 에셋들을 그 프로젝트에 넣을 수 있게 됩니다.

버전 관리 도구로써는? 글쎄...

이렇게 유니티 패키지를 사용하면 자신이 개발한 내용이나 기능, 에셋 등을 다른 사람에게 공유할 수 있게 됩니다.

하지만 유니티 패키지를 프로젝트의 버전 관리 도구처럼 사용하려고 해서는 안됩니다.

프로젝트의 버전 관리는 개발 내용의 최신화가 아주 중요한데, 패키지를 전달 받은 다른 개발자가 자신의 프로젝트에 적용하는 작업을 까먹고 안할 수도 있고, 전달 과정에서 몇몇 사람들을 빼먹고 전달하는 경우도 있을 수 있어서 프로젝트의 최신화를 공통적으로 유지하기 어렵습니다.

그리고 이 패키지를 임포트하는 작업은 같은 에셋이 존재하는 경우에 수정 사항을 완전히 덮어씌워버리기 때문에 작업 내용이 겹치거나 잘못된 작업이 임포트되었을 때, 되돌릴 방법이 없다는 것도 문제입니다.

그렇기 때문에 유니티 패키지는 프로젝트의 버전 관리를 위한 방법으로는 적절하지 못하며, 프로젝트 버전 관리는 SVN이나 깃을 사용하는 것이 좋습니다.

깃허브를 이용해서 유니티 프로젝트를 관리하는 방법을 소개하는 영상은 영상 링크를 통해서 확인하실 수 있습니다.

유니티 패키지 사용법

그러면 유니티 패키지는 어디에 사용하면 좋은지 궁금하신 분들이 계실 겁니다.

물론 저는 거기에 답변을 드려야겠죠.

유니티 패키지는 필요한 에셋들을 선택해서 각 에셋 사이의 참조나 종속성 연결을 끊기지 않게 가져올 수 있다는 점에 초점을 맞춰야 합니다.

그래서 필요한 에셋들을 다른 프로젝트에서 가져올 수 있는 것입니다.

예를 들어 예전에 만들었던 게임이 있다고 해봅시다.

그리고 그 다음 게임을 만들려고 하는데 예전에 만들었던 게임과 유사한 형태의 인벤토리 시스템을 넣으려고 한다고 가정해봅시다.

이러면 새 프로젝트에서 완전히 새롭게 인벤토리 시스템을 짜는 것보다 이전 프로젝트에 들어있는 인벤토리 에셋들을 유니티 패키지로 익스포트해서 가져오는 편이 훨씬 나을 겁니다.

또 다른 예시로는 새 프로젝트를 만들어두고 여기에는 인벤토리 시스템만을 구현하는 방식으로 아예 특수한 기능만 구현하는 유니티 프로젝트를 만드는 것입니다.

그리고 이 프로젝트에는 이 시스템을 어떻게 사용해야 하는지 알려주는 샘플 씬과 각종 에셋, 그리고 설명서까지 넣어둡니다.

그 다음에 이 인벤토리 시스템이 필요한 프로젝트가 생기면 이 인벤토리만 구현된 프로젝트에서 관련 에셋들을 유니티 패키지로 익스포트해서 인벤토리 시스템이 필요한 프로젝트에 임포트 시키는 거죠.

사실 대부분의 유니티 에셋 스토어에 올라온 에셋들이 이렇게 필요한 기능만 구현된 프로젝트에서 패키지만 익스포트하는 방식과 유사하게 동작합니다.

아웃트로

이번 영상에서는 유니티에서 에셋을 묶어서 전달하는 기능인 유니티 패키지에 대해서 알아보았습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

반응형
반응형

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번 영상에서는 개발할 때 활용할 수 있는 정규화라는 개념에 대해서 알아봅시다!

 

타임라인

0:00 인트로

0:10 정규화란?

0:47 벡터의 정규화

3:21 좌표의 정규화

5:12 아웃트로

 

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번 시간에는 게임 개발에서 사용할 수 있는 정규화라는 개념에 대해서 알아보도록 하겠습니다.

정규화란?

먼저 정규화라는 용어에 대해서 알아보겠습니다.

위키백과를 참고해보면 정규화는 어떤 대상을 일정한 규칙이나 기준에 따르는 정규적인 상태로 바꾸거나 비정상적인 대상을 정상적으로 돌리는 과정을 뜻한다고 합니다.

영어로는 Nomalization이라고 합니다.

이 정규화라는 개념은 여러 분야에서 각 분야에 맞게 사용되고 있습니다.

가장 대표적인 것은 데이터베이스 분야의 정규화로 데이터베이스를 설계할 때 여러 테이블에서 중복되는 데이터를 최소화시키는 프로세스를 가리킵니다.

게임이나 프로그램을 개발할 때도 여러 곳에서 이러한 정규화를 적용할 수 있습니다.

벡터의 정규화

앞에서 정규화를 영어로 하면 Noralization이라고 했을 때 짐작하신 분도 있었겠지만 역시 가장 먼저 이야기 해볼 것은 바로 벡터의 정규화 입니다.

벡터에 대해서는 [좌표와 속도를 다루는 도구 - 벡터] 영상에서 한 번 다룬 적이 있습니다.

벡터에 대한 자세한 내용은 해당 영상에서 확인할 수 있습니다.

벡터의 정규화는 어떤 한 벡터를 벡터의 길이로 나누어서 그 벡터의 길이를 1로 만드는 것입니다.

이렇게 길이가 1이 된 벡터를 단위 벡터라고 부르죠.

이런 식으로 정규화를 통해서 길이를 1이 된 벡터는 캐릭터의 이동과 방향에 주로 사용됩니다.

보통 키보드로 조작하는 방식의 게임은 W키와 S키를 이용해서 앞/뒤로 움직이고 A키와 D키를 이용해서 좌/우로 움직입니다.

그리고 W키를 누르면 수직 입력 값을 1로 받고 S키를 누르면 수직 입력 값을 -1로 받게 됩니다.

물론 손을 떼면 0이고 W키와 S키를 동시에 누르면 값이 상쇄되어서 0이 됩니다.

A키와 D키 역시 마찬가지로 수평 입력 값에 대해 동일하게 동작합니다.

그리고 W키와 S키로 동작하는 수직 입력과 A키와 D키로 동작하는 수평 입력을 묶어서 2차원 벡터로 이동 입력을 표현하게 됩니다.

여기서 이동 입력 키를 하나만 눌렀을 때의 입력 벡터의 길이는 언제나 1이라는 것을 알 수 있습니다.

이처럼 플레이어가 이동하고자 하는 입력 방향 벡터의 길이가 언제나 1이 되어야 캐릭터를 이동시킬 때, 입력 받은 방향에 캐릭터의 이동 속도를 곱하는 방식으로 쉽게 구현할 수 있게 됩니다.

그런데 캐릭터를 대각선 방향으로 이동시키기 위해서 W키와 A키, W키와 D키, A키와 S키, D키와 S키 같은 조합으로 동시에 누르게 되면 문제가 발생합니다.

만약 오른쪽 정면을 향해 이동하기 위해 W키와 D키를 동시에 눌렀다면, 정면 방향 벡터인 (0,1)과 오른쪽 방향 벡터인 (1,0)이 합쳐져서 (1,1)이 됩니다.

벡터 (1,1)의 길이는 밑변과 높이가 각각 1인 삼각형의 빗변의 길이로 나타내집니다.

이 길이는 루트 2로 약 1.414가 됩니다.

그래서 입력된 대각선 이동 벡터에 곧바로 이동 속도를 곱해서 캐릭터를 이동시키면 앞, 뒤, 왼쪽, 오른쪽 각 단일 방향으로 움직일 때보다 약 1.4배의 속도로 더 빠르게 움직일 수 있게 되는 겁니다.

이런 문제를 막기 위해서 이동 벡터의 길이가 1보다 길어지면 정규화를 통해서 이동 벡터의 길이를 1로 맞춰주는 방식을 자주 사용하게 됩니다.

이런 캐릭터의 이동 문제 외에도 속력과 방향을 정의되는 벡터에서 순수하게 방향만을 남겨서 사용하고자 하는 경우에는 이러한 벡터의 정규화 개념을 사용하게 됩니다.

좌표의 정규화

두 번째로 다뤄볼 정규화는 좌표의 정규화입니다.

게임을 개발하면서 우리는 여러가지 종류의 공간을 다루게 됩니다.

대표적으로는 게임을 플레이하면서 돌아다니게 되는 월드 공간과 UI가 그려지는 UI 공간이 있습니다.

이 두 공간의 좌표를 오가는 기능으로는 월드 공간에 존재하는 오브젝트를 UI 공간에서 나타내기 위한 기능으로 지도 기능이 있습니다.

플레이어나 오브젝트들이 움직이는 월드 공간의 크기는 기획에 따라 달라지기 마련이고 UI 공간은 디스플레이의 해상도에 따라 달라집니다.

간단하게 예를 들어서 3800x3800의 넓이를 가지는 월드 공간에서 움직이는 오브젝트를 UI 공간에서 800x800의 지도 UI에서 표시하고 싶다고 가정해봅시다.

오브젝트가 (2000, 1500)의 위치에 있을 때 지도 UI에 자신의 좌표를 그대로 보내버리면 800x800인 지도의 한참 바깥에 위치를 표시하게 됩니다.

그렇기 때문에 월드 공간에 존재하는 오브젝트의 위치는 좌표를 정규화시켜서 지도에 전달해야 합니다.

오브젝트 좌표의 X값과 Y값을 각각 월드 공간에 속하는 맵의 가로 폭과 세로 폭으로 나눠줍니다.

그러면 오브젝트의 좌표는 (0.52631, 0.39473)으로 변환되면서 좌표의 모든 값이 0에서 1사이 값의 형태를 가지게 됩니다.

이렇게 정규화된 좌표 값을 지도 UI에 넘겨주면 지도 UI에서는 이 값에 지도의 너비와 높이를 곱해줍니다.

그러면 오브젝트의 지도 위에서 좌표 값이 (421.05, 315.78)이 되면서 월드 상의 위치와 지도 상의 위치가 거의 흡사하게 표시되는 것을 볼 수 있습니다.

이런 식으로 서로 다른 공간에 있는 오브젝트의 위치를 표현할 때 좌표 값을 정규화해서 넘겨주는 것으로 동일한 위치에 표시할 수 있게 되는 것입니다.

이러한 좌표의 정규화 개념은 월드 공간과 UI 공간을 넘어서, 현실 공간에서 센서같은 장비로 계측된 위치를 월드 공간으로 옮기는 방식으로도 적용할 수 있습니다.

아웃트로

이번 영상에서는 정규화라는 개념과 게임 개발에서 사용되는 아주 간단한 예시만을 알아보았습니다.

이 외에도 정규화라는 개념은 게임 개발의 여러 분야에서 유용하게 사용할 수 있습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

반응형

'게임 제작 > 게임 수학' 카테고리의 다른 글

[Math] 정규화 (1) - 벡터와 좌표의 정규화  (1) 2021.10.04
[Math] 비트 연산  (0) 2021.06.22
  1. 일등하이 2021.10.05 08:25 신고

    잘보고가요^^ 깔끔한 정리입니다👍

반응형

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

지난 어몽어스 영상에 이어서 투표와 추방 기능을 계속 만들어 봅시다!

 

사용 엔진 버전 : 2019.3

 

타임라인

0:00 인트로

0:10 투표 기능 만들기

3:36 투표 스킵 기능 만들기

6:30 투표 시간 제한 만들기

10:41 아웃트로

 

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번 영상에서는 지난 강좌의 내용에 이어서 투표와 추방 기능을 계속 만들어 보겠습니다.

투표 기능 만들기

이번에는 투표하는 기능을 만들어보겠습니다.

먼저 IngameCharacterMover 스크립트로 이동해서 이 플레이어가 투표했는지를 의미하는 bool 타입의 isVote 변수와 이 플레이어가 몇 표를 받았는지를 의미하는 int 타입의 vote 변수를 선언하고 두 변수에 SyncVar 어트리뷰트를 붙여줍니다.

그리고 CmdVoteEjectPlayer 함수를 만들고 Command 어트리뷰트를 붙여줍니다.

이 함수에서는 투표한 플레이어의 isVote 값과 표를 받은 플레이어를 찾아서 Vote 값을 바꿔줍니다.

그 다음에는 GameSystem 스크립트로 이동해서 다른 모든 플레이어들에게 투표 내용을 알리기 위해서 RpcSignVoteEject 함수를 만들고 ClientRpc 어트리뷰트를 붙여줍니다.

그리고 IngameCharacterMover의 CmdVoteEjectPlayer 함수에서 RpcSignVoteEject 함수를 호출해줍니다.

잠시 MeetingUI로 이동해서 UpdateVote 함수를 만들어 줍니다.

그리고 이 함수에서는 MeetingPlayerPanel들에 몇 가지 작업을 해줘야 합니다.

이리저리 스크립트를 많이 이동해서 어지러울 수 있는데 이건 애초에 설계를 제대로 안하고 내키는대로 작업한 부작용입니다.

MeetingPlayerPanel 스크립트로 이동합니다.

그리고 GameObject 타입으로 이 플레이어가 투표했음을 알리는 voteSign 변수와 이 플레이어에게 어떤 플레이어가 투표했는지 알리는데 사용될 voterPrefab 변수, voterPrefab으로 만들어진 오브젝트들을 정렬하는데 사용될 Transform 타입의 voterParentTransform 변수를 선언해줍니다.

그 다음에는 UpdatePanel 함수를 만들어서 투표한 플레이어 캐릭터를 만들고 배치하도록 코드를 작성합니다.

그리고 UpdateVoteSign 함수를 만들고 voteSign 오브젝트를 활성화 시키게 코드를 작성합니다.

그 다음에는 MeetingUI의 UpdateVote 함수로 돌아가서 투표받은 플레이어의 UpdatePanel 함수를 호출해주고 투표한 플레이어는 UpdateVoteSign 함수를 호출해줍니다.

그리고 그 다음에는 GameSystem의 RpcSignVoteEject 함수로 가서 MeetingUI의 UpdateVote 함수를 호출해줍니다.

이어서 패널을 선택했을 때 뜨는 투표 버튼의 기능을 마저 만들어 보겠습니다.

MeetingPlayerPanel 스크립트로 이동해서 Select 함수를 만들고 CmdVoteEject 함수로 이 플레이어가 어떤 플레이어에게 투표했는지 알리고 투표 버튼을 비활성화하도록 코드를 작성합니다.

마지막으로 OnClickPlayerPanel 함수에서 이미 투표한 플레이어는 투표를 하지 못하도록 코드를 수정해줍니다.

코드를 모두 작성한 다음에는 저장하고 에디터로 이동합니다.

에디터로 돌아온 다음에는 PlayerPanel 프리팹을 찾아서 열고 프로퍼티에 플레이어가 투표했음을 알리는 표시와 투표한 플레이어 프리팹, 그리고 투표한 플레이어 오브젝트가 정렬될 트랜스폼을 할당해줍니다.

그리고 Select Button의 On Click 이벤트에 PlayerPanel의 Select 함수를 등록해줍니다.

작업이 끝나면 게임을 빌드합니다.

빌드가 완료된 이후에 게임을 실행해서 테스트해보면 투표하고자 하는 플레이어의 패널을 선택하고 체크 버튼을 누르면 그 캐릭터의 패널에 투표한 플레이어의 아이콘이 뜨는 모습을 볼 수 있습니다.

투표 스킵 기능 만들기

그 다음으로는 누구를 임포스터로 지목할 지 결정하지 못한 플레이어를 위한 투표 스킵 기능을 만들 차례입니다.

MeetingUI 스크립트로 이동합니다.

그리고 GameObject 타입으로 voterPrefab 변수와 skipVoteButton 변수 그리고 skipVotePlayers 변수를 선언하고, Transform 타입의 skipVoteParentTransform 변수를 선언합니다.

그리고 UpdateSkipVotePlayer 함수를 만들고 매개변수로 받은 플레이어의 투표함 표시를 활성화 한다음 투표 스킵 표시를 추가하는 코드를 작성합니다.

이어서 투표 스킵 버튼을 비활성화하고 투표를 스킵한 플레이어의 표시가 보이도록 코드를 작성합니다.

그 다음에는 GameSystem 스크립트로 이동해서 투표를 스킵한 플레이어 수를 카운트할 int 타입의 skipVotePlayerCount 변수를 선언하고 SyncVar 어트리뷰트를 붙여줍니다.

그리고 투표를 스킵한 플레이어를 클라이언트의 MeetingUI에 알려주고 업데이트 하기 위한 RpcSignSkipVote 함수를 만들고 ClientRpc 어트리뷰트를 붙여줍니다.

이 함수에서는 MeetingUI의 UpdateSkipVotePlayer를 호출해주면 됩니다.

그 다음으로는 IngameCharacterMover 스크립트로 이동해서 CmdSkipVote 함수를 만들고 Command 어트리뷰트를 붙여준 뒤 GameSystem의 skipVotePlayerCount의 값을 증가시키고 RpcSignSkipVote 함수를 호출해줍니다.

그리고 다시 MeetingUI 스크립트로 돌아와서 스킵 버튼을 눌렀을 때 동작할 OnClickSkipVoteButton 함수를 만들고 내 캐릭터의 CmdSkipVote 함수를 호출하도록 코드를 구현합니다.

물론 이 함수 역시 플레이어가 이미 투표한 경우라면 누르지 못하도록 코드를 작성해줍니다.

코드를 모두 작성한 다음에는 코드를 저장하고 에디터로 돌아갑니다.

에디터로 돌아온 다음에는 Meeting UI 오브젝트를 선택하고 각 프로퍼티에 필요한 것들을 찾아서 할당해줍니다.

Voter Prefab에는 Voter Img 프리팹을 할당하고, Skip Vote Button 프로퍼티에는 Skip Vote Button 오브젝트를 할당해줍니다.

그리고 Skip Vote Players 프로퍼티에는 Skipped Voting 오브젝트를, Skip Vote Parent Transform 프로퍼티에는 Skipped Voter 오브젝트를 할당해줍니다.

마지막으로 Skip Vote Button의 On Click 이벤트에 Meeting UI의 OnClickSkipVoteButton 함수를 등록해줍니다.

작업을 모두 마친 뒤에는 게임을 빌드합니다.

그리고 게임을 실행해서 테스트해보면 투표 스킵이 잘 작동하는 모습을 볼 수 있습니다.

물론 지금은 한 플레이어가 스킵하면 모든 플레이어에게서 스킵버튼이 바로 사라지고 스킵한 플레이어가 보이게 되면서 한 명만 스킵이 가능하지만 이 부분은 모든 플레이어가 투표한 뒤에 그 결과가 보이도록 만들면서 수정할 예정입니다.

시간 제한

그 다음으로는 투표를 하지 않는 플레이어를 자동으로 스킵처리하기 위해서 투표 시간 제한을 추가해보겠습니다.

먼저 회의와 관련된 시간 변수를 찾아보기 위해서 GameRuleStore 스크립트를 열어보겠습니다.

게임 규칙과 관련된 GameRuleData 구조체를 살펴보면 회의 시간인 meetingsTime과 투표 시간인 voteTime 변수를 볼 수 있습니다.

이 두 값을 이용해서 회의 시간과 투표 시간을 제한해보겠습니다.

GameSystem 스크립트로 이동해서 float 타입으로 남은 회의 시간과 투표 시간을 나타내는 데 사용될 remainTime 변수를 만들고 SyncVar 어트리뷰트를 붙여줍니다.

그리고 이 제한 시간을 계산할 코루틴 함수를 MeetingProcess_Coroutine이라는 이름으로 만들어 줍니다.

MeetingProcess_Coroutine 함수에서는 룸 매니저에서 가져온 게임 규칙 데이터의 meetingsTime과 voteTime 값을 이용해서 remainTime을 계산하도록 만들어줍니다.

그리고 회의가 시작된 직후에 회의 시간동안에는 투표를 하지 못하게 막기 위해서 플레이어들의 isVote를 true로 만들어줍니다.

그 다음에 회의 시간이 끝나고 투표 시간이 시작될 때 플레이어들의 isVote를 false로 만들어서 다시 투표가 가능하게 만들어 주고 투표받은 수나 스킵된 투표 수 역시 초기화해 줍니다.

만들어진 MeetingProcess_Coroutine 함수는 StartReportMeeting 함수에서 호출해줍니다.

그리고 중간에 회의 시간이 끝나고 투표 시간이 시작되었음을 알리기 위한 RpcStartVoteTime 함수와 투표 시간이 종료되었음을 알리는 RpcEndVoteTime 함수를 만들고 각각 ClientRpc 어트리뷰트를 붙여줍니다.

함수의 자세한 내용은 작업을 좀 더 진행한 이후에 채우기로 하고 MeetingProcess_Coroutine 함수에서 이 두 함수를 호출하도록 만들어줍니다.

그 다음에는 MeetingUI 스크립트로 넘어가서 상단에 회의 상태를 확인하기 위한 EMeetingState 열거형을 만들어줍니다.

그리고 방금 만든 열거형 타입으로 회의 상태를 표시할 meetingState 변수와 Text 타입으로 시간을 출력하기 위한 meetingTimeText 변수를 선언해줍니다.

그리고 ChangeMeetingState 함수를 만들어서 외부에서 회의 상태를 변경할 수 있게 만들어 준 뒤 Update 함수에서 남은 시간을 표시하도록 만들어 줍니다.

다시 GameSystem 스크립트로 이동해서 StartMeeting_Coroutine 함수에서 MeetingUI의 ChangeMeetingState 함수를 호출해서 회의 상태를 Meeting으로 변경하고 RpcStartVoteTime 함수에서는 Vote로 변경하게 코드를 작성합니다.

그리고 마지막으로 할 작업은 현재 투표를 하면 바로 결과가 보이는 것을 모든 투표가 완료된 이후에만 결과가 공개되도록 수정하는 것입니다.

먼저 MeetingPlayerPanel 스크립트로 이동해서 OpenResult 함수를 만들고 UpdatePanel 함수에 있는 voterParentTransform를 보이게 만들어주는 코드를 방금 만든 함수로 이동시킵니다.

그리고 MeetingUI 스크립트로 이동해서 CompleteVote 함수를 만든 뒤 각 패널의 OpenResult 함수를 호출하고 UpdateSkipVotePlayer 함수에서 스킵한 플레이어들을 보여주는 코드를 이 CompleteVote 함수로 이동시켜줍니다.

마지막으로 GameSystem 스크립트로 이동해서 RpcEndVoteTime 함수에서 MeetingUI의 CompleteVote 함수를 호출하도록 코드를 작성하고 MeetingProcess_Coroutine 함수에서 RpcEndVoteTime 함수가 호출되기 전에 아직 투표하지 않은 플레이어가 있다면 강제로 스킵에 투표하도록 해줍니다.

코드를 모두 작성한 다음에는 코드를 저장하고 에디터로 돌아갑니다.

에디터에서는 Meeting UI 오브젝트 아래에 시간을 표시할 Text를 추가해줍니다.

그리고 추가한 Text 오브젝트는 Meeting UI 컴포넌트의 Meeting Time Text 프로퍼티에 할당해줍니다.

그리고 모든 작업이 끝나면 게임을 빌드합니다.

빌드가 완료되고 실행해서 테스트해보면 회의 시간이 끝나기 전에는 투표가 불가능하며, 투표 시간이 되면 그때부터 투표가 가능해집니다.

그 다음에 투표 시간이 끝날 때 투표 결과가 공개되며 시간이 끝날 때까지 투표를 하지 않은 플레이어는 자동으로 스킵 처리되는 모습을 확인할 수 있습니다.

아웃트로

이번 영상에서는 투표와 추방 기능을 만들기 위해서 다른 플레이어에게 투표하는 기능과 투표 스킵 기능, 그리고 투표 시간 제한을 만들어 보았습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

반응형
반응형

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번 강좌에서는 깃허브에서 브랜치를 다루는 방법을 알아봅시다!

 

타임라인

0:00 인트로

0:09 브랜치

1:48 메인 브랜치

2:12 브랜치 나누기

4:04 깃허브 웹페이지에서의 브랜치 작업

6:15 깃허브 데스크탑에서의 브랜치 작업

8:04 아웃트로

 

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번에는 깃허브에서 브랜치를 다루는 방법에 대해서 알아보도록 하겠습니다.

브랜치

깃허브에서 브랜치를 다루기 전에 브랜치라는 단어에 대해서 이야기해보겠습니다.

브랜치라는 단어는 영어 단어로 분기 혹은 가지라는 뜻을 가지고 있습니다.

쉽게 생각하면 여러 개의 가지로 나누어지는 나무를 생각할 수 있습니다.

지난 깃허브 영상에서는 리포지토리를 만드는 방법과 커밋, 푸시, 풀 등의 기본적인 깃 동작들을 알아보았는데 이 모든 작업은 깃에서 가장 기본이 되고 중심이 되는 가지인 메인 브랜치 위에서 이루어진 것입니다.

여기서 이 브랜치라는 단어의 뜻을 생각하면 이후의 작업에서는 경우에 따라서 이 브랜치가 마치 나뭇가지처럼 여러 갈래로 갈라질 수 있음을 추측할 수 있습니다.

그럼 이 브랜치라고 부르는 개발의 나뭇가지는 왜 필요한 것일까요?

사실 혼자서하는 간단한 개인 작업이나 연습 프로젝트를 위한 리포지토리라면 메인 브랜치 위에서만 작업해도 충분합니다.

하지만 적어도 출시를 하기 위한 1인 프로젝트나 여러 개발자들과 함께 하는 프로젝트에서는 메인 브랜치에서 모두 작업하는 일은 바람직하지 못합니다.

먼저 출시를 위한 1인 프로젝트의 경우를 보면 어떤 기능을 추가하거나 버그를 수정하기 위해서 코드를 작성하거나 수정하는 일이 곧바로 출시되서 앱스토어에 올라가는 버전에 반영이 되게 됩니다.

물론 깃허브에는 잘못된 작업이나 만들었지만 마음에 들지 않는 기능을 다시 되돌리기 위한 히스토리 기능이 있지만 여전히 가장 중심이 되는 메인 브랜치에 영향을 끼친다는 점이 꺼림칙하게 느껴질 수 밖에 없습니다.

그리고 여러 개발자가 함께 협업하는 경우 역시 모든 개발자가 메인 브랜치에서 동시에 작업을 한다면 내가 작업 중인 파트를 누군가 건드려서 훼손하거나 동시에 여러 종류의 커밋이 한 브랜치의 히스토리에 뒤섞여서 문제가 발생했을때 이것을 되돌리기 어려워지게 됩니다.

이러한 여러 가지 문제를 해결하기 위한 도구가 바로 브랜치입니다.

메인 브랜치

앞에서도 말했다시피 리포지토리를 만들었을 때 가장 기본적으로 만들어지는 브랜치는 메인 브랜치입니다.

이 메인 브랜치는 보통 언제든지 배포 혹은 빌드되어 출시 가능한 버전의 코드만이 올라와 있어야 합니다.

그렇기 때문에 이 메인 브랜치를 대상으로 커밋이나 풀, 푸시 같은 작업을 하는 일은 리포지토리를 생성해서 프로젝트를 세팅하기 위한 초기가 아니면 발생하지 않도록 주의해야 합니다.

브랜치 나누기

그러므로 메인 브랜치는 놔둔채로 최신 버전의 메인 브랜치에서 새로운 브랜치를 따서 해당 브랜치에서 작업을 한 뒤에 모든 작업이 끝나고 검증이 완료되면 메인 브랜치로 합치는 방식으로 작업이 진행되어야 합니다.

그럼 이 브랜치를 나누는 기준은 어떻게 될까요?

물론 브랜치를 나누는 기준은 개발자마다, 팀마다, 프로젝트마다, 회사마다 다 다를 수 있습니다.

여기서는 브랜치 나누는 아주 간단한 방식을 한 가지만 이야기 해보겠습니다.

그 방법은 브랜치를 메인 브랜치, 디벨롭 브랜치로 나누는 것입니다.

앞에서도 이야기 했다시피 메인 브랜치는 출시나 배포를 위해 두고 완전히 검증된 코드만 올라오도록 유지합니다.

그리고 디벨롭 브랜치에서는 실제 개발 작업이 이루어지며 이 버전의 브랜치에서 빌드된 프로그램은 내부 테스트를 통해 검증하게 되고 검증이 완료된 코드를 메인 브랜치로 보내서 출시와 배포가 이루어지는 방식입니다.

이렇게 브랜치를 이원화시키고 검증된 작업만 메인 브랜치로 적용함으로써 버그를 최소화할 수 있게되는 겁니다.

물론 이 디벨롭 브랜치에서도 모든 개발자들이 한 브랜치에서 작업하는게 아니라 각자의 기준에 따라서 브랜치를 따게 됩니다.

그 기준은 작업자 별로 따로 브랜치를 딸 수도 있고, 만들어야 하는 기능이나 고쳐야하는 버그 별로 브랜치를 딸 수도 있습니다.

보통 기능이나 고쳐야하는 버그 같은 작업 단위로 따는 브랜치를 토픽 브랜치라고 부릅니다.

일반적으로는 두 방식을 섞어서 디벨롭 브랜치에서 기능이나 수정할 버그 별로 토픽 브랜치를 따고 그 토픽 브랜치에 여러 개발자가 붙으면 또 거기서 각 개발자별 브랜치를 따는 방식으로 진행됩니다.

물론 여러 개발자가 한 토픽에서 작업할 수도 있지만, 작업하다가 서로 같은 부분을 수정해서 합칠 때 발생하는 충돌이 없도록 작업을 섬세하게 분배할 필요가 있습니다.

서비스가 유지되는 동안에는 계속 유지하게 되는 메인 브랜치나 디벨롭 브랜치와는 다르게 이런 토픽 브랜치는 해당 기능이 완성되거나 버그가 해결되서 디벨롭 브랜치에 합쳐지는 순간 브랜치를 삭제하게 됩니다.

깃허브 웹 페이지에서의 브랜치 작업

그럼 이제 깃허브에서 브랜치를 생성하는 방법을 알아보겠습니다.

먼저 깃허브 웹페이지에서 브랜치를 만들고자하는 리포지토리를 선택합니다.

그러면 파일과 폴더 목록 위에 main이라고 써진 드롭다운 버튼이 보입니다.

이것은 지금 선택된 브랜치가 리포지토리의 가장 기본 브랜치인 main 브랜치로 선택되어 있다는 뜻입니다.

그리고 그 옆에 있는 1branch라는 버튼을 누르면 이 리포지토리에 있는 모든 브랜치 목록을 볼 수 있습니다.

앞 페이지로 돌아가서 main 브랜치 드롭다운을 클릭하고 입력창에 현재 브랜치 목록에 없는 이름을 입력하면 새로운 브랜치를 생성할 수 있습니다.

이렇게 다른 브랜치인 상태에 파일을 하나 열고 내용을 수정해보겠습니다.

새로운 브랜치에서 이렇게 작업을 진행하고 다시 원래의 main 브랜치로 돌아가보면 두 브랜치의 파일 작업 상태가 서로 다른 것을 볼 수 있습니다.

그리고 이 새로 만든 브랜치에서의 작업이 끝나면 이렇게 작업한 내용은 메인 브랜치로 합쳐야 하는데 그 작업을 머지라고 부르고 이 머지 작업을 요청하는 것을 풀 리퀘스트라고 부릅니다.

풀 리퀘스트를 생성하기 위해서는 페이지 상단 탭에서 Pull request를 클릭하고 뜨는 풀 리퀘스트 페이지에서 New pull request 버튼을 클릭하면 됩니다.

그리고 compare에는 작업한 브랜치를 선택하고 base에는 작업한 브랜치를 합칠 브랜치를 선택합니다.

그러면 새 브랜치에서 작업한 내용과 원본 브랜치의 내용을 비교할 수 있게 됩니다.

변경사항을 비교한 다음 Create pull request 버튼을 누른 뒤에 생성할 풀 리퀘스트의 타이틀과 코멘트를 통해 어떤 작업을 진행했는지 작성하고 한 번 더 Create pull request 버튼을 눌러주면 풀 리퀘스트가 생성 됩니다.

이렇게 풀 리퀘스트를 생성하고 나면 리포지토리의 Pull request 목록에 생성된 풀 리퀘스트를 볼 수 있습니다.

이렇게 만들어진 풀 리퀘스트에 개발 팀원들은 이 작업에 대해서 코멘트를 남길 수 있고 관리자는 풀 리퀘스트를 검토한 후 풀 리퀘스트를 브랜치에 머지하거나 Close pull request로 풀 리퀘스트를 거절할 수도 있습니다.

그리고 Merge request 버튼을 누르면 풀 리퀘스트의 작업 내용을 합칠 수 있게 됩니다.

이렇게 원래의 브랜치로 머지를 끝낸 브랜치는 Delete branch로 닫을 수 있습니다.

깃허브 데스크탑에서의 브랜치 작업

그럼 이번에는 깃허브 데스크탑에서 브랜치 작업을 해보겠습니다.

깃허브 데스크탑에서 작업할 리포지토리를 선택하고 나면 Current repository 옆에 Current branch 가 main으로 되어있음을 볼 수 있습니다.

여기서도 웹 페이지에서처럼 새로 만들 브랜치의 이름을 적고 Create new branch를 해주면 됩니다.

하지만 깃허브 데스크탑에서 브랜치를 만들어도 웹 페이지에서는 바로 보이지 않을텐데, 깃허브 데스크탑에서 방금 만든 브랜치는 로컬에만 존재하는 상태이기 때문입니다.

웹 페이지에서도 보이고 다른 작업자들에게 내 브랜치를 보이게 만들기 위해서는 Publish branch를 해줘야 합니다.

Publish branch를 하고 나면 웹 페이지에서도 추가된 브랜치를 볼 수 있게 됩니다.

그 다음에 새로 만든 브랜치에서 작업한 뒤에 커밋하고 푸시하면 웹 페이지에서 변경된 점을 볼 수 있습니다.

그리고 깃허브 데스크탑에서도 브랜치를 오가면 작업이 분리되는 모습을 볼 수 있습니다.

역시 깃허브 데스크탑에서도 작업이 끝나면 작업 내용을 원래 브랜치로 합치는 풀 리퀘스트를 해야합니다.

Create pull request 버튼을 누르면 웹 페이지가 열리면서 풀 리퀘스트를 생성할 수 있습니다.

이후의 과정은 웹 페이지에서의 과정과 같이 브랜치의 작업 내용을 정리해서 풀 리퀘스트를 하고 머지를 진행하면 됩니다.

다만, 웹 페이지에서 풀 리퀘스트를 머지하고 브랜치를 삭제하더라도 깃허브 데스크탑에서는 브랜치가 그대로 존재합니다.

이 브랜치를 다시 퍼블리시해서 사용할 수도 있지만 상단 메뉴 바에서 [Branch > Delete] 항목을 선택해서 깃허브 데스크탑에서의 브랜치를 완전히 삭제할 수도 있습니다.

아웃트로

이번 영상에서는 깃허브에서 작업 내용이 섞이지 않게 하기 위해서 브랜치를 이용해서 작업하는 방법을 알아보았습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

반응형
반응형

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번 영상에서는 대규모 게임 회사에서 고퀄리티 지형을 만드는 데 사용되는 툴을 알아봅시다!

 

타임라인

0:00 인트로

0:45 월드 머신

2:38 월드 크리에이터

3:25 아웃트로

 

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

여러분들은 여러 게임이나 영화를 보면서 엄청나게 넓은 지형과 월드맵을 어떻게 제작하는지 궁금해 해보신 적이 있으신가요?

영화에서 실제로 존재하는 공간이라면 그 현장에 가서 촬영을 하고 CG를 씌우겠지만, 그 공간을 직접 제작해야 하는 게임이나 우리의 상상 속에만 존재하는 공간이라면 어떻게 만들어질까요?

게임이나 영화 속에 나오는 깎아지른 산이 빼곡한 산악 지대, 황량하고 광활한 사막, 매서운 바람이 몰아치는 설원과 빙하지대, 들끓는 용암이 흐르는 용암 지대, 아무도 가본 적없는 우주의 행성과 같은 지형이 어떻게 만들어지는지 알려드리기 위해 이번 영상에서는 상당수의 대규모 프로덕션에서 고퀄리티 지형을 제작하는데 사용되는 툴을 소개해보겠습니다.

월드 머신

첫 번째로 소개할 툴은 월드 머신입니다.

구글에서 World Machine이라는 키워드로 검색하면 제일 상단에 World Machine : The Premier 3D Terrain Generator라는 이름으로 월드 머신 공식 페이지 링크가 뜨는 것을 볼 수 있습니다.

그 링크로 접속하면 월드 머신을 어떻게 사용하는지 간단한 프리뷰가 보이는 홈페이지를 볼 수 있습니다.

여기서 Free download 버튼을 누르면 무료 버전의 월드 머신을 다운로드 받을 수 있습니다.

무료 버전의 월드 머신은 비상업적으로 사용하는 경우에 무료로 제공되고 1025x1025의 해상도 제한이 있습니다.

이러한 제한없이 사용하고 싶으시다면 유료 버전을 구매해서 사용하시면 됩니다.

먼저 무료 버전을 통해서 사용법을 익힌 뒤에 유료 버전을 구매해서 사용하시는 것도 좋습니다.

일단 무료 버전을 다운로드 받아서 설치합니다.

설치가 완료된 다음 월드 머신을 실행해보면 노드를 이어서 지형을 제작하는 작업 공간이 보입니다.

그리고 왼쪽 상단에는 지금 노드로 만들어진 월드가 작게 보이는데 좀 더 크게 보고 싶다면 상단 메뉴 바에서 사각형 4개가 모여있는 스플릿 버튼을 누르면 월드의 모습을 좀 더 크게 원하는 각도로 돌려볼 수 있는 3D뷰를 볼 수 있게 됩니다.

이 3D 뷰를 켜고 각 노드를 선택하면 해당 노드의 결과물을 볼 수 있고 Scene View 노드를 선택하면 모든 작업이 처리된 최종 결과물을 볼 수 있습니다.

그리고 각 노드를 선택해서 변수 값을 바꿔주면 실시간으로 지형이 바뀌는 모습을 볼 수 있습니다.

그리고 노드를 추가하면 바다나 강 역시도 추가할 수 있습니다.

이런 작업을 통해 만들어진 높이 맵을 게임 엔진으로 불러와서 사용하게 됩니다.

이렇게 만들어진 지형을 유니티 엔진과 언리얼 엔진에서 불러오면 이렇게 됩니다.

월드 크리에이터

두 번째로 소개할 툴은 월드 크리에이터 입니다.

월드 머신과 마찬가지로 지형을 제작하는 툴인데 월드 크리에이터는 월드 머신과 같은 교육용 무료 버전을 제공하지 않습니다.

월드 머신과 월드 크리에이터를 모두 사용해본 지인의 의견으로는 월드 크리에이터 쪽이 조금 더 고퀄리티의 결과물을 내기에 좋다고 합니다.

그래서인지 우리가 잘 아는 대규모 개발사들은 상당수 월드 크리에이터를 사용하고 있습니다.

기능 제한이 있는 스탠다드 버전은 $149로 $119인 월드 머신의 인디 버전 버전보다 비싸지만 거의 모든 기능을 자유롭게 사용할 수 있는 프로페셔널 버전은 $289로 $299인 월드 머신의 프로페셔널 버전보다는 저렴합니다.

고퀄리티의 지형 제작에 도전해보고 싶으신 분들이라면 구매해서 사용해보시면 좋을 듯합니다.

아웃트로

이번 영상에서는 거대한 지형을 제작하는데 사용되는 툴인 월드 머신과 월드 크리에이터를 소개해봤습니다.

조금 더 여유가 생긴다면 월드 머신이나 월드 크리에이터로 월드를 제작해서 게임 엔진에 올리는 작업을 강좌로 만들어보도록 하겠습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

반응형

'게임 제작' 카테고리의 다른 글

대규모 게임 회사의 고퀄리티 지형 제작 비법  (0) 2021.08.18
반응형

 

개발단에 가입하여 베르의 게임 개발 유튜브를 지원해주세요!

https://www.youtube.com/channel/UC9j3...

 

리소스 패키지 : https://drive.google.com/file/d/1jwGm...

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번 영상에서는 임포스터로 의심되는 플레이어에게 투표하고 추방하는 기능을 만들어 봅시다!

 

사용 엔진 버전 : 2019.4

 

타임라인

0:00 인트로

0:12 회의 UI 배치

2:56 플레이어 패널 띄우기

6:57 플레이어 패널 선택 기능 만들기

10:00 아웃트로

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번에는 신고 이후에 플레이어들끼리 투표하고 가장 많은 표를 받은 플레이어를 추방하는 기능을 만드는 과정을 진행해보겠습니다.

회의 UI 배치

작업에 들어가기에 앞서 영상 하단의 링크에서 리소스 패키지를 다운로드 받아서 프로젝트에 임포트해줍니다.

리소스 임포트가 완료된 다음에는 회의 UI를 배치해보겠습니다.

먼저 Canvas 오브젝트 아래에 Image 게임오브젝트를 생성하고 화면 전체를 덮도록 세팅한 다음 색을 투명하게 만들어줍니다.

그 아래에는 임포트한 리소스들을 이용해서 실제 게임 화면과 유사하게 배치해줍니다.

그리고 플레이어 패널을 만들어야 합니다.

패널을 만들고 플레이어 이미지를 올린 다음 닉네임을 표시할 텍스트를 추가해줍니다.

그리고 빈 게임오브젝트를 추가하고 Horizontal Layout Group 컴포넌트와 Content Size Fitter 컴포넌트를 붙여줍니다.

그리고 Horizontal Layout Group의 Child Alignment는 Middle Left로 변경하고 Content Size Fitter의 프로퍼티는 Min Size로 변경해줍니다.

그리고 이 레이아웃 그룹 오브젝트의 Pivot X 값을 0으로 맞춰줍니다.

그러면 이 레이아웃 그룹 오브젝트 밑에 다른 플레이어가 투표했음을 표시하는 이미지를 추가하면 제대로 정렬되어서 추가되는 모습을 볼 수 있습니다.

그 다음에는 빈 게임오브젝트도 추가해서 그 아래에 투표 버튼과 취소 버튼도 올려줍니다.

그리고 투표했을 때 표시되는 UI와 죽은 플레이어에게 표시되는 부가 UI까지 올려줍니다.

플레이어 패널을 완성한 다음에는 빈 게임오브젝트를 만들고 Grid Layout Group 컴포넌트를 붙여줍니다.

그리고 Sell Size를 348x63으로 변경하고 플레이어 패널을 복제해서 2열 5행으로 배치되게 크기를 맞추고 간격을 조절해줍니다.

그리고 그 아래쪽에 Skip vote 버튼과 투표를 스킵한 플레이어를 보여주는 UI를 만들어줍니다.

투표를 스킵한 플레이어를 보여주는 UI를 만들 때는 플레이어 패널에서 다른 플레이어가 투표했음을 보여주는 UI와 똑같이 만들어주면 됩니다.

기본적인 배치를 마친 다음에는 만든 플레이어 패널과 투표 표시용 캐릭터 이미지를 프리팹으로 만들어주고 배치되어 있는 오브젝트는 삭제해줍니다.

그리고 Skipped Voting UI도 숨겨줍니다.

플레이어 패널 띄우기

이제 이 Meeting UI의 기능을 차례대로 만들어보겠습니다.

먼저 플레이어 패널에 붙일 MeetingPlayerPanel 스크립트를 생성하고 스크립트 에디터를 엽니다.

스크립트 에디터가 열리고 나면 스크립트의 상단에 UnityEngine.UI 네임스페이스를 using 선언해줍니다.

그리고 멤버 변수로 캐릭터 이미지 색을 바꾸는데 쓰일 Image 타입의 characterImg 변수와 닉네임을 표시하는데 쓰일 Text 타입의 nicknameText 변수, 죽은 플레이어를 표시할 때 사용될 GameObject 타입의 deadPlayerBlock과 신고자를 표시하기 위한 reporterSign 변수를 추가해줍니다.

그리고 어떤 플레이어의 패널인지 구분하기 위한 용도로 IngameCharacterMover 타입의 targetPlayer 변수도 만들어줍니다.

그 다음에는 SetPlayer 함수를 만들어서 characterImg의 머티리얼을 인스턴싱하고 매개변수로 받아온 캐릭터를 저장한 뒤에 캐릭터 이미지의 색을 바꾸고 닉네임을 세팅해줍니다.

그리고 임포스터인 플레이어가 다른 임포스터 플레이어의 패널을 볼 때는 이름이 빨간색으로 표시되도록 만들어줍니다.

그리고 패널의 대상이 되는 플레이어가 죽은 상태라면 플레이어 패널을 가리는 회색 패널이 켜지도록 만들어줍니다.

마지막으로는 해당 플레이어가 신고자라면 확성기 모양의 이미지가 활성화되도록 해야하는데 관련 변수가 없는 상태이니 IngameCharacterMover 클래스로 이동해서 bool 타입으로 isReporter 변수를 추가하고 SyncVar 어트리뷰트를 붙여줍니다.

그리고 아래 쪽에 있는 CmdReport 함수에서 isReporter 변수를 true로 변경하게 만들어줍니다.

다시 MeetingPlayerPanel 스크립트로 돌아와서 targetPlayer가 isReporter라면 reporterSign을 활성화시키도록 코드를 작성합니다.

코드를 모두 작성한 다음에는 저장하고 에디터로 돌아가서 Meeting Player Panel 오브젝트에 작성한 컴포넌트를 붙여줍니다.

그리고 각 프로퍼티를 할당해줍니다.

잠시 앞에서 빼먹은 확성기 모양의 신고자 표시 이미지를 추가하고 비활성화한 뒤 프로퍼티에 할당해줍니다.

그 다음에는 MeetingUI라는 이름으로 C# 스크립트를 생성하고 스크립트 에디터를 엽니다.

스크립트 에디터가 열리고 나면 스크립트의 상단에 UnityEngine.UI 네임스페이스를 using 선언해줍니다.

그리고 멤버 변수로는 플레이어 패널 프리팹을 담고 있을 GameObject 타입의 playerPanelPrefab 변수와 생성된 플레이어 패널들의 부모 오브젝트가 될 Transform 타입의 playerPanelsParent 변수, 그리고 생성된 플레이어 패널들을 저장하고 있을 List<MeetingPlayerPanel> 타입의 meetingPlayerPanels 변수를 선언해줍니다.

변수 선언을 끝낸 다음에는 Open 함수를 만들고 내 캐릭터의 패널을 먼저 만들어서 배치해주고 그 후에 FindObjectsOfType 함수로 다른 플레이어들을 찾아서 각 플레이어의 패널을 만들어 줍니다.

그 다음에는 IngameUIManager 스크립트로 이동해서 MeetingUI를 캐싱해서 접근하기 쉽게 만들어줍니다.

그리고 GameSystem 스크립트로 이동해서 StartMeeting_Coroutine 함수를 만들고 3초 후에 Report UI를 닫고 Meeting UI를 열도록 코드를 작성합니다.

그리고 이 StartMeeting_Coroutine 함수를 RpcSendReportSign 함수에서 호출하도록 만들어 줍니다.

코드를 모두 작성한 다음에는 저장하고 에디터로 돌아갑니다.

에디터로 돌아온 다음에는 Meeting UI 오브젝트에 작성한 컴포넌트를 붙이고 프로퍼티를 할당해줍니다.

그리고 Canvas 오브젝트에 붙어있는 IngameUIManager 컴포넌트에 MeetingUI를 캐싱해줍니다.

작업을 끝낸 다음에는 게임을 빌드합니다.

빌드가 완료되면 게임을 실행하고 테스트합니다.

시체를 발견하고 리포트 버튼을 누르면 리포트 UI가 뜬 뒤에 Meeting UI가 뜨고 죽은 플레이어는 어두운 색으로 표시되고 신고한 플레이어에게는 확성기 마크가 뜬 모습을 확인할 수 있습니다.

패널 선택 기능 만들기

이제 플레이어 패널을 선택하는 기능을 만들 차례입니다.

플레이어 패널을 선택했을 때 투표를 위한 버튼을 뜨게 해야합니다.

MeetingPlayerPanel 스크립트를 엽니다.

그리고 GameObject 타입으로 투표 버튼 그룹을 컨트롤할 voteButtons 변수를 선언하고 패널을 클릭했을 때 동작할 OnClickPlayerPanel 함수를 만들어줍니다.

이 함수에서는 먼저 voteButtons를 활성화시키도록 코드를 작성해줍니다.

코드를 작성한 다음에는 저장하고 에디터로 돌아갑니다.

그리고 프리팹에서 Vote Buttons 프로퍼티에 Player Panel 프리팹 아래에 있는 Vote Buttons 게임오브젝트를 할당해줍니다.

그 다음에는 Player Panel 오브젝트에 Button 컴포넌트를 붙인 다음 Transition을 None으로 변경하고 On Click 이벤트에 Meeting Player Panel의 OnClickPlayerPanel 함수를 등록해줍니다.

작업을 마치면 게임을 빌드해서 테스트 합니다.

회의 창이 뜬 이후에 플레이어 패널을 클릭해보면 투표를 위한 체크 버튼과 X 버튼이 뜨는 모습을 볼 수 있습니다.

그런데 지금은 다른 플레이어 패널을 선택했을 때 앞에서 선택한 플레이어 패널의 버튼이 사라지지도 않고 죽은 플레이어도 선택해서 투표를 할 수 있습니다.

그리고 죽은 플레이어도 다른 플레이어에게 투표할 수 있죠.

스크립트로 돌아가서 이 부분들을 수정해보겠습니다.

먼저 죽은 플레이어의 패널이 클릭되지 않도록 하는 부분은 SetPlayer 함수에서 처리하면 됩니다.

deadPlayerBlock을 활성화하기 위해서 판정한 값을 isDead 변수에 따로 저장해서 사용하도록 코드를 수정합니다.

그리고 isDead 값을 GetComponet 함수로 가져온 버튼의 interactable에 넣어줍니다.

그 다음은 한 패널을 선택했을 때 다른 패널의 선택을 해제하는 것입니다.

이것을 위해서는 다른 패널에 접근이 가능해야하는데 생성된 패널들은 MeetingUI에서 가지고 있으니 그쪽을 통해서 접근하는 것이 좋습니다.

먼저 MeetingPlayerPanel 클래스에 Unselect 함수를 만들어서 voteButtons를 비활성화 시키도록 만들어줍니다.

그 다음에는 MeetingUI 클래스로 이동해서 SelectPlayerPanel 함수를 만들고 선택한 패널을 제외한 다른 패널을 비활성화시키도록 코드를 작성합니다.

그리고 다시 MeetingPlayerPanel 클래스의 OnClickPlayerPanel 함수로 이동해서 MeetingUI의 SelectPlayerPanel 함수를 호출하도록 만들어줍니다.

마지막으로 죽은 플레이어가 투표를 하지 못하게 막기 위해서는 OnClickPlayerPanel 함수에서 플레이어가 죽은 상태라면 투표 기능이 동작하지 못하게 만들어줍니다.

코드를 모두 작성한 다음에는 저장하고 에디터로 돌아갑니다.

그리고 프리팹의 Vote Buttons 아래에 있는 Cancel Button을 선택하고 On Click 이벤트에 Unselect 함수를 등록해줍니다.

작업을 모두 마치면 게임을 빌드합니다.

그리고 게임을 실행해서 테스트해보면 한 패널을 선택하고 다른 패널을 선택하면 이전에 선택한 다른 패널의 선택이 취소되고 죽은 플레이어의 패널은 선택되지 않는 것을 볼 수 있습니다.

그리고 X 버튼을 누르면 패널 선택이 취소되는 모습도 볼 수 있습니다.

마지막으로 죽은 플레이어는 다른 플레이어를 선택할 수 없는 모습도 볼 수 있습니다.

아웃트로

이번 영상에서는 회의에서 임포스터로 의심되는 플레이어에게 투표해서 추방하는 기능을 만들기 위해 회의 UI를 만들고 플레이어 패널을 선택하는 기능을 만들어 보았습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

반응형
반응형

 

사용 버전 : 2019.4

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번 영상에서는 유니티의 인보크에 대해서 알아보도록 하겠습니다.

기본 인보크

우선 인보크란 유니티 엔진에서 모든 유니티 스크립트의 기본 클래스인 MonoBehaviour 클래스에서 제공되는 함수로써 기본적으로 원하는 함수를 일정 시간 후에 호출하거나 일정 시간마다 반복해서 호출할 수 있게 해주는 기능을 제공합니다.

우선 인보크 기능을 테스트해보기 위해서 프로젝트 뷰에서 InvokeTester라는 이름으로 C# 스크립트를 생성하고 스크립트 에디터를 엽니다.

스크립트 에디터가 열리고 나면 CreateCube 함수를 만들고 큐브를 랜덤한 위치에 생성하도록 코드를 작성합니다.

그리고 Start 함수로 가서 Invoke 함수를 호출해줍니다.

이 때 Invoke로 호출될 함수의 이름을 문자열로 넣고 얼마나 시간이 흐른 뒤에 호출될 지를 매개변수로 넣어주면 됩니다.

지금은 3초로 설정하겠습니다.

코드를 저장하고 에디터로 돌아갑니다.

에디터로 돌아온 다음에는 씬에 빈 게임오브젝트를 하나 생성하고 거기에 InvokeTester 컴포넌트를 붙여줍니다.

그 다음 게임을 플레이시켜보면 3초 뒤에 큐브가 스폰되는 모습을 볼 수 있습니다.

이것이 가장 기초적인 인보크 사용 방법입니다.

반복 호출되는 인보크

그 다음 알아볼 것은 반복 호출되는 인보크입니다.

다시 스크립트 에디터로 돌아갑니다.

방금 배운 것처럼 매개변수에 호출할 함수의 이름과 시간만 넣으면 함수가 일정 시간 후에 한 번 호출됩니다.

여기에 Invoke 함수 대신에 InvokeRepeating 함수로 바꾸고 세 번째 매개변수에 1을 넣어줍니다.

이렇게 하면 InvokeRepeating이 호출되고 3초 후에 CreateCube 함수가 호출되며 그 뒤로 1초마다 계속해서 반복 호출됩니다.

코드를 저장하고 에디터로 돌아가서 게임을 실행해보겠습니다.

그러면 3초가 지난 후에 1초마다 계속 새로운 큐브가 생성되는 모습을 볼 수 있습니다.

인보크 멈추기

그 다음에는 동작 중인 인보크를 멈추는 방법을 알아보겠습니다.

다시 스크립트도 돌아갑니다.

인보크를 멈추기 위해서는 CancelInvoke 함수를 사용하면 됩니다.

이 때 매개변수에 아무것도 넣지 않으면 이 게임오브젝트에서 동작하고 있는 모든 인보크들을 멈추게하고 매개변수에 함수 이름을 넣으면 그 함수 이름으로 실행된 인보크들만 멈추게 할 수 있습니다.

그럼 인보크가 멈추는 것을 확인해보기 위해서 코드를 작성하겠습니다.

먼저 CreateCube 함수를 복사해서 큐브 대신 구체를 만들어내는 CreateSphere 함수를 만들어줍니다.

그리고 업데이트 함수에서 키보드 숫자 1을 누르면 CreateCube 함수가 InvokeRepeating 되게 만들어 주고 2를 누르면 CreateSphere 함수가 InvokeRepeating 되게 만들어줍니다.

그리고 숫자 3을 누르면 CreateCube 함수가 CancelInvoke 되고 4를 누르면 CreateSphere 함수가 CancelInvoke 되게 해줍니다.

마지막으로 ESC를 누르면 동작 중인 모든 인보크가 멈추게 만듭니다.

코드를 저장하고 에디터로 돌아가서 게임을 실행합니다.

그리고 1과 2를 누르면 큐브와 구체가 계속해서 생성되는 모습을 볼 수 있습니다.

이 상태에서 3을 누르면 큐브의 생성이 멈추고 4를 누르면 구체의 생성이 멈춥니다.

다시 1과 2를 눌러 큐브와 구체를 생성되게 만든 다음 ESC 키를 누르면 큐브와 구체의 생성이 동시에 멈추는 것을 볼 수 있습니다.

인보크 상태 확인하기

이번에는 인보크가 동작 중인지 확인하는 방법을 알아보겠습니다.

인보크가 동작 중인지 확인하기 위해서는 IsInvoking 함수를 사용하면 됩니다.

이 함수 역시 CancelInvoke 함수와 마찬가지로 매개변수로 함수 이름을 넣으면 그 함수에 대한 인보크가 동작 중인지 확인할 수 있고 매개변수를 사용하지 않으면 아무 인보크나 동작하고 있는지를 체크할 수 있습니다.

이번에는 숫자 5를 누르면 CreateCube 함수에 대한 인보크를 체크하고 6을 누르면 CreateSphere 함수에 대한 인보크를 체크해서 로그를 출력하도록 코드를 작성합니다.

그리고 숫자 7을 누르면 매개변수 없이 인보크를 체크하도록 만듭니다.

코드를 모두 작성한 다음에는 저장하고 에디터로 돌아가서 게임을 실행합니다.

그리고 인보크를 실행하기 전에 5, 6, 7을 순서대로 눌러보면 어떠한 인보크도 동작하고 있지 않음을 로그로 확인할 수 있습니다.

그 다음에 1을 눌러 CreateCube 함수를 인보크로 동작시키고 5, 6, 7을 누르면 CreateCube 인보크 확인 로그와 모든 인보크 확인 로그를 통해서 인보크가 동작하고 있음을 확인할 수 있습니다.

그리고 2를 누르고 CreateSphere 함수까지 인보크로 동작시키고 5, 6, 7을 누르면 모든 인보크가 동작하고 있음을 로그로 확인할 수 있습니다.

이번에는 3을 눌러서 CreateCube 함수의 인보크를 중지시키고 5, 6, 7을 누르면 CreateCube 인보크가 동작하지 않는다는 로그를 볼 수 있습니다.

마지막으로 4를 눌러서 CreateSphere 함수의 인보크를 중지시키고 5, 6, 7을 누르면 모든 인보크가 동작하지 않는것을 로그로 확인할 수 있습니다.

멈추지 않는 인보크

추가로 유니티 엔진에서 게임오브젝트의 Update 함수과 코루틴 같은 기능은 게임오브젝트나 컴포넌트가 비활성화되면 동작을 멈추는 것을 알고 있으실 겁니다.

하지만 인보크 기능은 해당 게임오브젝트나 컴포넌트가 비활성화되어도 동작을 멈추지 않습니다.

인보크를 멈추기 위해서는 반드시 CancelInvoke 함수를 호출하거나 게임오브젝트 자체를 파괴해야 합니다.

하지만 코루틴

이렇게 인보크를 사용하면 원하는 함수를 일정 시간이 지난 후에 호출하거나 원하는 시간 간격으로 호출할 수 있는데 이 기능은 코루틴을 사용해서도 똑같이 구현할 수 있습니다.

그리고 유니티 공식 문서를 보면 성능 향상과 유지보수를 위해서는 코루틴을 사용할 것을 권장하고 있습니다.

우선 성능적인 측면을 보자면 인보크는 함수를 문자열로 된 이름으로 찾아서 사용하고 있습니다.

이렇게 문자열 함수 이름으로 함수를 찾아서 사용하기 위해서는 C#의 리플렉션이라는 기능을 사용하게 되는데 이렇게 문자열 함수 이름으로 리플렉션을 통해서 함수를 동작시키는 과정은 직접 함수를 호출하는 것에 비해서 수 천 배 정도 느리다고 합니다.

물론 컴퓨터의 사양이 많이 상승한 최근에는 유의미한 성능 저하는 당장 일어나지 않겠지만 인보크를 남용하면서 게임을 만들다보면 게임의 사양이 많이 올라갔을 때 최적화를 위해서 인보크를 사용하는 코드를 대부분 갈아엎어야 할 수도 있습니다.

아웃트로

이번 영상에서는 유니티 엔진에서 원하는 함수를 일정 시간이 지난 후에 호출하거나 원하는 시간 간격으로 호출할 수 있게 만들어주는 인보크에 대해서 알아보았습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

타임라인

0:00 인트로

0:09 기본 인보크

1:12 반복 호출되는 인보크

1:55 인보크 멈추기

3:22 인보크 상태 확인 하기

4:51 멈추지 않는 인보크

5:14 하지만 코루틴

6:06 아웃트로

반응형
반응형

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

지난 강좌까지 크루원을 죽이는 기능을 만들었으니 이번 영상에서는 크루원의 시체를 발견하면 신고하는 기능을 만들어봅시다.

시체 감지해서 리포트 버튼 활성화 시키기

제일 먼저 해야할 작업은 플레이어가 시체를 감지했을 때 리포트 버튼을 활성화시키는 것입니다.

그러기 위해서는 시체 오브젝트에 감지할 수 있는 콜라이더를 추가해줘야 합니다.

프로젝트 뷰에서 Deadbody 프리팹을 찾아서 선택합니다.

그리고 캐릭터를 감지할 CircleCollider2D 컴포넌트를 부착해준 뒤 is Trigger 프로퍼티를 체크해줍니다.

그리고 캐릭터가 감지하게 될 거리로 반지름을 6으로 설정해줍니다.

그 다음에는 인스펙터 뷰 상단의 레이어에서 Add Layer를 선택하고 Deadbody 레이어를 추가해줍니다.

레이어를 추가한 다음에는 프리팹을 다시 선택하고 프리팹의 레이어를 Deadbody로 설정해줍니다.

그 다음에는 Deadbody 레이어의 콜라이더가 Player 레이어의 콜라이더와 만났을 때만 반응하게 만들어 주기 위해서 상단 메뉴 바에서 [Edit > Project Settings] 항목을 선택해서 프로젝트 세팅 창을 열어줍니다.

그리고 Physics 2D 카테고리의 제일 아래에서 Deadbody 레이어는 Player 레이어에만 반응하도록 만들어줍니다.

콜라이더 세팅이 끝난 다음에는 Deadbody 스크립트를 열어줍니다.

Deadbody 클래스에서는 OnTriggerEnter2D 콜백 함수와 OnTriggerExit2D 콜백 함수를 만들어줍니다.

그리고 감지된 플레이어가 들어오거나 나갈 때마다, 자기 자신이고 유령이 아닌 상태라면 리포트 버튼을 활성화시키거나 비활성화시켜 줘야합니다.

우선 코드를 저장하고 에디터로 돌아갑니다.

그리고 ReportButtonUI라는 이름으로 C# 스크립트를 생성하고 스크립트 에디터를 다시 열어줍니다.

스크립트 에디터가 열리고 나면 스크립트의 상단에 UnityEngine.UI 네임스페이스를 using 선언해줍니다.

그리고 멤버 변수로 Button 타입의 reportButton을 선언해주고 SetInteractable 함수를 만들어서 매개변수인 isInteractable 값에 따라서 버튼을 활성화시키거나 비활성화시키도록 코드를 작성해줍니다.

그 다음에는 IngameUIManager 클래스로 이동해서 ReportButtonUI를 캐싱해서 쉽게 접근할 수 있도록 해줍니다.

캐싱 작업이 끝나면 Deadbody 클래스로 이동해서 OnTriggerEnter2D 콜백 함수에서는 SetInteractable 함수로 리포트 버튼을 활성화 시키게 만들어주고 OnTriggerExit2D 콜백 함수에서는 SetInteractable 함수로 리포트 버튼을 비활성화시키게 만들어줍니다.

코드를 모두 작성한 다음에는 저장하고 에디터로 돌아갑니다.

에디터로 돌아온 다음에는 Report Button을 찾아서 ReportButtonUI 컴포넌트를 붙여주고 프로퍼티를 할당합니다.

그리고 캔버스에 붙어있는 IngameUIManager에 방금 붙여준 ReportButtonUI를 프로퍼티에 할당해줍니다.

그리고 메인 카메라와 All See Camera에서 레이어가 Deadbody인 시체를 보이게 만들기 위해서 두 카메라를 선택하고 Culling Mask에 Deadbody 레이어를 추가합니다.

작업이 끝나면 게임을 빌드합니다.

빌드가 완료되고 게임을 실행해서 테스트해보면 시체가 시야에 잡히기 시작하면 리포트 버튼이 활성화되고 멀어지면 비활성화되는 모습을 볼 수 있습니다.

리포트 UI 배치

그 다음 작업은 신고 버튼을 누른 뒤에 시체 리포트 UI를 띄우는 것입니다.

먼저 영상 하단의 링크에서 작업에서 사용될 리소스 패키지를 다운로드 받아서 임포트합니다.

리소스 임포트가 끝나면 Canvas 아래에 Report UI라는 이름으로 Image 게임오브젝트를 만들고 화면 영역 전체를 덮도록 만들어 줍니다.

그리고 이미지의 알파 값을 0으로 내려서 투명하게 만들어 줍니다.

그 다음에는 그 아래에 이미지 오브젝트를 생성하고 임포트한 스프라이트들을 넣어서 게임의 리포트 UI와 비슷하게 만들어줍니다.

리포트 UI 기능 구현

이미지를 모두 배치한 다음에는 ReportUI라는 이름으로 C# 스크립트를 생성하고 스크립트 에디터를 엽니다.

스크립트 에디터가 열리고 나면 스크립트의 상단에 UnityEngine.UI 네임스페이스를 using 선언해줍니다.

그리고 멤버 변수로 Image 타입의 deadbodyImg와 Material 타입의 material을 선언해줍니다.

그 다음에는 Open 함수를 만들어서 캐릭터가 움직이지 못하게 만든 다음 머티리얼을 인스턴싱해주고 매개변수로 받은 deadbodyColor로 deadbodyImg의 색을 변경하도록 만들어줍니다.

그 다음에는 Close 함수를 만들어서 이 ReportUI를 닫는 기능도 만들어줍니다.

이 다음 단계로는 IngameUIManager 클래스로 이동해서 reportUI에 접근하기 쉽도록 캐싱하는 코드를 작성합니다.

이렇게 ReportUI 클래스의 작업이 끝난 다음에는 버튼을 눌렀을 때 모든 플레이어의 화면에서 리포트 UI가 뜨게 만들어야 합니다.

리포트 UI를 뜨게 만들기 전에 모든 유저에게 알려주기 위해서 발견한 시체의 색을 전달할 필요가 있습니다.

IngameCharacterMover 클래스로 이동해서 EPlayerColor 타입으로 foundDeadbodyColor 변수를 추가해줍니다.

그리고 Deadbody 클래스로 이동해서 OnTriggerEnter2D 콜백 함수에서 발견한 시체의 색을 발견자의 캐릭터에 전달해줘야 합니다.

그전에 아직 Deadbody 클래스에 죽은 플레이어 색이 저장되어 있지 않기 때문에 EPlayerColor 멤버 변수를 추가하고 RpcSetColor 함수에서 매개변수로 받은 값을 저장해줍니다.

그리고 OnTriggerEnter2D 콜백 함수에서 자신의 캐릭터에 발견한 시체의 색을 저장해줍니다.

그 다음에는 다시 IngameCharacterMover 클래스로 돌아가서 Report 함수와 CmdReport 함수를 만들어줍니다.

Report 함수에서는 매개변수로 발견한 죽은 크루원의 색상을 넣어서 CmdReport 함수를 호출하게 코드를 작성합니다.

그리고 CmdReport 함수에는 Command 어트리뷰트를 붙여줍니다.

이렇게 CmdReport 함수를 통해서 서버로 전달된 리포트 신호를 다른 플레이어들에게 전달해주면 됩니다.

GameSystem 클래스로 이동해서 StartReportMeeting 함수를 만들어 줍니다.

이 함수를 통해서 리포트 미팅이 시작됩니다.

지금은 간단하게 다른 플레이어들에게 시체 발견 신호를 보내는 역할만을 하게 될 겁니다.

RpcSendReportSign 함수를 만들고 ClientRpc 어트리뷰트를 붙여준 뒤 StartReportMeeting 함수에서 호출하도록 만들어 줍니다.

그리고 RpcSendReportSign 함수에서는 ReportUI의 Open 함수를 호출하게 만들어줍니다.

그 다음에는 ReportButtonUI 클래스로 이동합니다.

여기서는 버튼을 눌렀을 때 호출될 OnClickButton 함수를 만들고 내 캐릭터의 Report 함수를 호출하게 만들어 줍니다.

다시 IngameCharacterMover의 CmdReport 함수로 돌아가서 GameSystem의 StartReportMeeting 함수를 호출해줍니다.

코드를 모두 작성한 다음에는 코드를 저장하고 에디터로 돌아갑니다.

에디터로 돌아온 다음에는 Report UI 오브젝트에 방금 작성한 ReportUI 컴포넌트를 붙여주고 시체 이미지와 크루원 머티리얼을 프로퍼티에 할당해줍니다.

그리고 Report Button을 선택하고 On Click 이벤트에 Report Button UI의 OnClickButton 함수를 등록해줍니다.

그 다음에는 Canvas를 선택해서 IngameUIManager 컴포넌트의 ReportUI 프로퍼티에 Report UI 오브젝트를 할당해줍니다.

작업을 마친 다음에는 게임을 빌드합니다.

빌드가 완료된 다음 게임을 실행해서 테스트해보면 리포트 버튼을 누른 뒤에 모든 플레이어의 화면에 리포트 UI가 뜨는 모습을 볼 수 있습니다.

아웃트로

이번 영상에서는 시체를 발견했을 때 리포트 버튼이 활성화되고 버튼을 누르면 모든 플레이어의 화면에 리포트 UI가 뜨는 기능을 만들어 보았습니다.

다음 영상에서는 여기에 이어서 회의를 하는 기능을 만들어 보도록 하겠습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

타임라인

0:00 인트로

0:12 시체를 감지해서 리포트 버튼 활성화 시키기

3:08 리포트 UI 배치

3:52 리포트 UI 기능 구현

7:30 아웃트로

반응형

+ Recent posts