본 포스트는 베르님의 Make the 어몽어스를 정리한 포스트입니다.
https://www.youtube.com/watch?v=alCanpd_MnI&list=PLYQHfkihy4Aw6QjsZqwwbD4ihpwvm7N0U&index=9
지난 시간 캐릭터 색상 구현 부분에서 일부 버그가 확인되어 해당 부분을 고치겠습니다.
현재 게임을 실행 후 설정 창을 켜고 캐릭터를 움직이면 조작이 되는 것을 확인할 수 있습니다. 원래 설정 창이 떴을 때 캐릭터가 움직이면 안되기 때문에 해당 부분을 수정하도록 하겠습니다.
먼저 GameRoomSettingUI 스크립트를 찾아서 연 후 해당 내용을 추가합니다.
public void Open(){
AmongUsRoomPlayer.MyRoomPlayer.lobbyPlayerCharacter.isMoveable = false;
gameObject.SetActive(true); // UI object 활성화
}
public override void Close(){ // 부모 클래스의 Close 함수 재정의
AmongUsRoomPlayer.MyRoomPlayer.lobbyPlayerCharacter.isMoveable = true;
gameObject.SetActive(false); // UI object 비활성화
}
현재 부모 class인 SettingsUI에 이미 close가 정의되어 있기에 SettingsUI의 close 함수에 virtual을 추가합니다.
public virtual void Close(){
StartCoroutine(CloseAfterDelay());
}
그리고 에디터로 돌아와서 Setting Button의 On Click 이벤트를 GameRoomSettingUI.Open으로 변경합니다.
게임을 실행하면 다음과 같이 실행 창이 뜬 상태에서 캐릭터의 조작이 동작하지 않는 것을 확인할 수 있습니다.
현재 게임을 실행해보면 높은 확률로 Customize UI가 켜졌을 때 캐릭터가 달리고 있는 상태로 멈춘 모습이 확인됩니다. Customize UI가 켜졌을 때 달리는 애니메이션이 아니라 서있는 애니메이션이 나와야 하기에 해당 부분을 수정하겠습니다.
isMovable이 false로 변경될 때 animator의 isMove 파라미터를 false로 변경하면 해결됩니다.
먼저 CharacterMover 스크립트를 연 후 다음과 같이 수정합니다. 현재 isMovable을 private으로 변경 후 public 변수인 IsMoveable을 새로 정의하였기에, isMoveable을 호출하던 다른 곳들의 코드를 IsMoveable을 통해 호출하도록 변경합니다. (isMoveable -> IsMoveable로 변경) (visual studio code의 경우 하단의 PROBLEMS 창에서 어느 스크립트가 호출하고 있는 지 확인이 가능합니다.)
private bool isMoveable; // 외부에서 호출하지 못하도록 변경
public bool IsMoveable{
get {return isMoveable;}
set{
if(!value){
// isMovable이 false일 때만 애니메이터의 isMove를 false로 변경
animator.SetBool("isMove",false);
}
isMoveable = value;
}
}
게임을 실행하면 Customize UI를 켰을 때 달리는 애니메이션이 더 이상 발생하지 않는 것을 확인할 수 있습니다.
저의 경우 플레이어 시작 isMoveable이 false로 지정되어 있는지 게임 시작 시에는 유저가 움직이지 않는 문제가 발견 되어 isMoveable을 처음 선언할 때 true 값으로 주었습니다.
private bool isMoveable = true; // 외부에서 호출하지 못하도록 변경
게임을 여러 개 빌드한 후 새로운 플레이어가 접속할 때마다 Customize UI를 켜보면 방장을 제외한 다른 클라이언트에서 새로 접속한 플레이어의 색이 제대로 업데이트 되지 않는 모습을 확인할 수 있습니다. 추가로 한 클라이언트가 방에서 나가면 그 플레이어가 선택했던 색상이 선택 해제가 되어야 하는데 여전히 사용중인 것으로 표시됩니다.
먼저 AmongUsRoomPlayer 스크립트를 엽니다. 해당 스크립트는 다음의 과정으로 동작합니다.
- 새로운 플레이어 접속 시 서버 역할을 겸하는 호스트에서 Lobby Player Character를 생성하면서 플레이어의 기본 색상을 정함
- 이렇게 정해진 색은 다른 클라이언트에서 SetPlayerColor_Hook 함수를 통해 통지 받아 UI에서 업데이트함
Hook을 통해 통지 받아 업데이트를 하는데 몇몇 클라이언트에서 제대로 업데이트가 되지 않을까 하는 의문이 드는데 이러한 문제는 네트워크 프로그래밍에서 항상 고민해야하는 부분입니다.
현재 코드를 살펴보면 UpdateColorButton 함수가 AmongUsRoomManger의 roomSlots에 등록된
RoomPlayer를 찾아 색상 버튼을 업데이트하도록 짜여있습니다. 이 RoomManager의 roomSlot에 RoomPlayer가 등록되는 시점은 RoomPlayer의 Start 함수가 실행될 때인데 서버에서는 이 RoomSlots 등록과 playerColor 변경이 순서대로 일어날 것이라는 보장이 있으나 클라이언트에서는 그 순서가 보장되지 않습니다. 따라서 클라이언트에서는 새로 생성된 플레이어가 RoomSlot에 등록되기도 전에 UpdateColorButton 함수가 호출될 수도 있습니다.
여기서는 UpdateColorButton 함수처럼 버튼 전체를 업데이트 하는 방법보다 받아온 color 값으로 필요한 버튼만 업데이트하도록 변경하겠습니다. Customize UI 스크립트에서 UpdateSelectColorButton 함수를 만들고 매개변수로 받은 color 값의 버튼만 비활성화하도록 코드를 작성합니다.
public void UpdateSelectColorButton(EPlayerColor color){
colorSelectButtons[(int)color].SetInteractable(false);
}
그 다음 AmongUsRoomPlayer 스크립의 SetPlayerColor_Hook 함수를 다음과 같이 수정합니다.
public void SetPlayerColor_Hook(EPlayerColor oldColor, EPlayerColor newColor){
// UpdateSelectColor Button 함수 호출하도록 변경
LobbyUIManager.Instance.CustomizeUI.UpdateSelectColorButton(newColor);
}
다음으로 플레이어가 접속을 종료했을 때 버튼 선택을 해제하는 부분을 구현해야합니다. Customize UI 스크립트에 다음 함수를 추가합니다.
public void UpdateUnselectColorButton(EPlayerColor color){
colorSelectButtons[(int)color].SetInteractable(true); // color 값의 버튼 활성화
}
해당 함수는 플레이어가 방을 나가면서 플레이어의 오브젝트가 파괴되면 호출될 AmongUsRoomPlayer의 OnDestroy 함수에서 호출되도록 만듭니다. 이를 위해 AmongUsRoomPlayer 스크립트에서 다음의 내용을 추가합니다.
private void OnDestroy(){
if(LobbyUIManager.Instance != null){
LobbyUIManager.Instance.CustomizeUI.UpdateUnselectColorButton(playerColor);
}
}
게임을 여러개 실행후 플레이어의 색상 변경 UI를 살펴보면 제대로 업데이트 되는 것을 확인할 수 있습니다.
6번째 캐릭터를 방에 접속시켜보면 모든 캐릭터가 오른쪽 방향을 보면서 스폰되는 것을 확인할 수 있습니다. 이를 해결하기 위해 AmongUsRoomPlayer 스크립트의 SpawnLobbyPlayerCharacter 함수를 보면 캐릭터를 생성할 때 캐릭터가 생성될 위치(spawnPos)만 가져오고 캐릭터가 바라볼 방향은 전혀 건드리지 않는 것을 알 수 있습니다.
방향 결정을 위해서는 캐릭터가 생성되는 의자의 위치를 알아야합니다. SpawnPositions 스크립트의 index 변수를 사용하면 캐릭터가 몇 번째 의자에서 소환되어야 하는 지 알 수 있습니다. index는 외부에서 건드리면 안되기 때문에 public으로 가져오기만 할 수 있는 get 프로퍼티를 만들어 index를 가져오도록 만듭니다.
// SpawnPositions 스크립트에 추가
public int Index{get {return index;}}
그 다음 AmongUsRoomPlayer 스크립트에서 다음의 내용을 추가합니다.
// SpawnPosition의 index를 구함
var spawnPositions = FindObjectOfType<SpawnPositions>();
int index = spawnPositions.Index;
Vector3 spawnPos = spawnPositions.GetSpawnPosition();
// 새로 생성되는 캐릭터의 방향 정하도록 만듦
// index < 5: 원래 방향, index >= 5: 방향 거꾸로
playerCharacter.transform.localScale = index < 5 ? new Vector3(0.5f,0.5f,1f) : new Vector3(-0.5f,0.5f,1f);
게임을 실행하면 다음과 같이 반대편 의자에서 보는 방향이 다르게 캐릭터가 spawn되는 것을 확인할 수 있습니다.
게임을 실행 후 캐릭터의 색상 변경 버튼을 누르고 다른 색상 변경 버튼을 누르면 이전에 선택했던 버튼 위의 x자 표시가 해제되지 않는 버그가 확인되었습니다. 따라서, 해당 부분을 마저 수정하겠습니다. 현재 새로 선택한 색상의 버튼 활성화 기능만 있고, 이전 색상의 버튼을 비활성화하는 기능이 없어서 그런 것으로 보입니다. 비활성화 코드 작성을 위해 AmongUsRoomPlayer 스크립트를 연 후 다음과 같이 수정합니다.
public void SetPlayerColor_Hook(EPlayerColor oldColor, EPlayerColor newColor){
LobbyUIManager.Instance.CustomizeUI.UpdateUnselectColorButton(oldColor); // 이전 색상 비활성화
LobbyUIManager.Instance.CustomizeUI.UpdateSelectColorButton(newColor); // UpdateSelectColor Button 함수 호출하도록 변경
}