어몽어스 - 온라인 UI (2)

이도희·2022년 1월 14일
0

Among Us 프로젝트

목록 보기
3/10
post-thumbnail

본 포스트는 베르님의 Make the 어몽어스를 정리한 포스트입니다.
https://www.youtube.com/watch?v=ISSCUVEzjq8&list=PLYQHfkihy4Aw6QjsZqwwbD4ihpwvm7N0U&index=4

앞선 시간에서 온라인 버튼 작동에 대한 작업을 진행하였습니다. 이번 시간에는 해당 부분을 이어서 진행하겠습니다.

1. 방 만들기 UI 작업

먼저 Canvas 아래 Image Object를 추가합니다.

Canvas / UI / Image / (Create Room UI)

해상도 변경을 고려해 앵커를 stretch-stretch로 설정하고 left, top, right, bottom을 모두 0으로 설정합니다. 검은색 배경으로 동작하게 됩니다.

다음으로 해당 오브젝트 밑에 배너와 글자를 추가해줍니다.

Canvas / Create Empty / Imposter Count, Max Player Count

Imposter Count, Max Player Count / UI / Text

다음으로 임포스터 수를 설정하기 위해 옆에 버튼을 추가해주겠습니다. 버튼의 경우 source image로는 pattern001을 사용하였고, 테두리 부분의 alpha 값을 0으로 지정해줍니다.

Imposter Count, Max Player Count / Create Empty / Buttons

Buttons 아래에 UI / Button

다음으로 숫자 버튼을 따로 나열하는 작업을 대신하고자 Buttons 게임 오브젝트에 horizontal layout group 컴포넌트와 Content size fitter 컴포넌트를 추가합니다. Content size fitter를 min, min으로 설정합니다. (레이아웃의 최소 너비와 높이에 기반하여 조정하는 것을 의미합니다.)
(+ spacing을 조절해 숫자 간의 간격을 조절할 수 있습니다.)

Imposter count와 Max Player count에 모두 동일한 작업을 한 후 위에서 1과 10에 alpha값을 255로 다시 조정하여 테두리를 보이게 만듭니다.

맵 배너에는 임포스터 수와 최대 인원 수에 맞게 크루원과 임포스터를 보이게 만듭니다. 앞의 과정과 비슷하게 진행이 되는데 먼저 맵 배너 아래 이미지를 넣고 sprites 폴더의 크루원 이미지를 소스 이미지로 설정합니다. 또한, 이전 시간에 만들었던 material을 넣어줍니다.

Map Banner Frame / Map Banner / Crews / UI / image

아까와 동일하게 horizontal layout group과 content size fitter 컴포넌트를 추가하여 spacing을 적당히 조절한 후 다음 사진과 같이 배치합니다.


마지막으로 확인과 취소 버튼을 생성합니다. 이때, 두 버튼 모두 해상도를 고려하여 앵커를 설정합니다. 취소의 경우 왼쪽 아래를, 확인 버튼의 경우 오른쪽 아래로 지정합니다.

마지막으로 모든 버튼의 highlighted 색을 초록색으로 변경해줍니다.

2. 크루원 이미지 색상 변경 기능 구현

먼저 설정한 최대 인원과 설정한 임포스터 수에 따라 배너에 보이는 크루원 수와 색을 변경하기 위해 다음의 코드를 작성합니다.

Online UI / Scripts (폴더 생성) / CreateRoomUI (C# scripts 생성)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; // 선언

public class CreateRoomUI : MonoBehaviour
{
    [SerializeField]
    private List<Image> crewImgs; 
    [SerializeField]
    private List<Button> imposterCountButtons; 
    [SerializeField]
    private List<Button> maxPlayerCountButtons;
    
    private CreateGameRoomData roomData;

    void Start()
    {
        roomData = new CreateGameRoomData(){imposterCount = 1, maxPlayerCount = 10}; // 기본 값 
        UpdateCrewImages();
    }
    
    // 맵 배너 위의 크루원 이미지가 임포스터 수와 플레이어의 수에 따라 변경되도록 함
    private void UpdateCrewImages(){
        int imposterCount = roomData.imposterCount;
        int idx = 0;
        while(imposterCount != 0){ // 임포스터 수를 모두 채울때 까지
            if(idx >= roomData.maxPlayerCount){
                idx = 0;
            }
            if(crewImgs[idx].material.GetColor("_PlayerColor") != Color.red && Random.Range(0,5) == 0) // 크루원을 랜덤으로 가져와 빨간 색으로 변경
            {
                crewImgs[idx].material.SetColor("_PlayerColor",Color.red);
                imposterCount --;
            }
            idx++;
        }

        for (int i = 0;  i < crewImgs.Count; i++){ 
            if(i < roomData.maxPlayerCount){
                crewImgs[i].gameObject.SetActive(true); // 설정한 플레이어 수 만큼만 크루원 이미지를 활성화
            }
            else{
                crewImgs[i].gameObject.SetActive(false); // 나머지는 비활성화
            }
        }
    }
}

// 이 클래스를 통해 새로 만든 방 데이터를 저장하고, 방 생성이 완료될 때 새로 만들어지는 방에 전달하게 됨
public class CreateGameRoomData{
    public int imposterCount;
    public int maxPlayerCount;
}

다음으로 테스트를 위해 Create Room UI 오브젝트에 생성한 scripts를 컴포넌트로 넣은 다음 이미지를 교차로 해서 넣어줍니다. (위, 아래 순서대로 추가하기 해주기 위함입니다.)

실행해보면 의도와 다르게 모든 크루원의 이미지가 빨간색으로 변해버립니다.

이 현상은 유니티 엔진에서 인스턴스화 하지 않은 오브젝트에 적용한 material을 수정하면 원본 material이 변경되는 특성 때문에 생깁니다.

이를 해결하기 위해서는 material을 인스턴스화 해서 원본이 아닌 복제된 material을 사용하도록 해야합니다.

    void Start()
    {
    // 크루 이미지의 material을 instantiate 함수를 통해 
    // 복제된 material instance를 만들어 크루원 이미지들의 material을 바꿔주는 코드를 추가 작성합니다. 
        for (int i = 0; i < crewImgs.Count; i++){
            Material materialInstance = Instantiate(crewImgs[i].material);
            crewImgs[i].material = materialInstance;
        }
        roomData = new CreateGameRoomData(){imposterCount = 1, maxPlayerCount = 10}; // 기본 값 
        UpdateCrewImages();
    }

다음과 같이 정상 동작하는 것을 확인할 수 있습니다. 하지만, 원본 material 색상이 다른 색인 경우 흰색 빨간색이 아니게 나오게 됩니다. (저의 경우 아까 변경을 했어서 현재는 제대로 나오는 것으로 보이지만 다른 색이 나오는 경우가 발생할 수 있습니다.) 따라서, update crew images함수에서 크루원의 색상을 변경하기 전 크루원의 색상을 미리 흰색으로 만드는 코드를 추가하겠습니다.

private void UpdateCrewImages(){
// 크루원들의 색상 모두 흰색으로 초기화하는 코드 추가
 for (int i = 0; i < crewImgs.Count; i++){
            crewImgs[i].material.SetColor("_PlayerColor", Color.white);
        }
        .
        .
        .
        }

3. 최대 인원 수 선택 기능 구현

다음으로 유저가 최대 인원 수를 입력하면 그에 따른 크루원의 수만 배너에 보이게 하는 코드를 작성해보겠습니다. 앞선 CreateRoomUI 스크립트에서 start함수 밑에 다음의 함수를 작성합니다.

 // 최대 인원에 해당 버튼의 이미지 테두리를 보이게 함
    public void UpdateMaxPlayerCount(int count){
        roomData.maxPlayerCount = count; // 매개변수로 받은 최대 인원 수를 room data에 저장
        for(int i = 0; i < maxPlayerCountButtons.Count; i++){
            if(i == count - 4){
                maxPlayerCountButtons[i].image.color = new Color(1f,1f,1f,1f);
            }
            else{
                maxPlayerCountButtons[i].image.color = new Color(1f,1f,1f,0f);
            }
        }
        UpdateCrewImages();

    }

다음으로 최대 인원수를 선택하는 버튼에 On Click()에 Create Room UI를 추가한 다음 UpdateMaxPlayerCount함수를 지정해주고 각 버튼 별로 해당되는 숫자를 설정합니다.

다음으로 CreateRoomUI 오브젝트 안의 scripts 컴포넌트의 Max Player Count Buttons에 해당되는 버튼들을 넣어줍니다. (이때, 다른 버튼을 끌어올때 계속해서 inspector창이 바뀌는 것을 방지하고자 위의 잠금 버튼을 누른 후 버튼을 선택하여 넣어줍니다.)

게임을 실행해보면 다음과 같이 인원 수에 따라 버튼의 프레임과 크루원의 이미지가 변경되는 것을 확인할 수 있습니다.

4. 임포스터 수 선택 기능 구현

어몽어스에서 방을 만들어 보면 임포스터 수가 1인 경우 전체 인원 수에는 제약이 없지만, 2인 경우는 7인 이상, 3인 경우는 9인 이상을 선택하도록 제한 사항이 있습니다. 이를 고려하여 다음과 같이 코드를 작성합니다.

 // 임포스터 수 설정 시 해당 버튼의 이미지 테두리를 보이게 함 
    public void UpdateImposterCount(int count){
        roomData.imposterCount = count; // 매개변수로 받은 임포스터 수를 room data에 저장
        for(int i = 0; i < imposterCountButtons.Count; i++){
            if(i == count - 1){
                imposterCountButtons[i].image.color = new Color(1f,1f,1f,1f);
            }
            else{
                imposterCountButtons[i].image.color = new Color(1f,1f,1f,0f);
            }
        }
        int limitMaxPlayer = count == 1 ? 4 : count == 2 ? 7 : 9; // 1인 경우 4, 2인 경우 7, 그 외(즉 3인 경우) 9
        if(roomData.maxPlayerCount < limitMaxPlayer){ // 만약 지정된 최대인원 수가 제약사항보다 작은 경우에는
            UpdateMaxPlayerCount(limitMaxPlayer); // 해당 제한에 맞게 최대 인원 수 변경
        }
        else{ // 최대인원 수가 이미 제약사항을 넘은 경우에는 그냥 그 인원 수 사용
            UpdateMaxPlayerCount(roomData.maxPlayerCount);
        }
        for(int i = 0; i < maxPlayerCountButtons.Count; i++){
            var text = maxPlayerCountButtons[i].GetComponentInChildren<Text>();
            if(i < limitMaxPlayer - 4){ // 제약 사항보다 작은 수의 버튼은 비활성화 및 text를 회색으로 변경
                maxPlayerCountButtons[i].interactable = false;
                text.color = Color.gray;
            }
            else{
                maxPlayerCountButtons[i].interactable = true;
                text.color = Color.white;
            }
        }
        UpdateCrewImages();
    }

최대 인원 수와 동일하게 Imposter count 버튼에도 On Click()에 해당 함수를 넣고 매개 변수를 알맞게 설정하고, Create Room UI에도 해당 버튼들을 추가합니다. 게임을 실행하면 다음과 같이 임포스터 수에 따라 최대 인원 수의 제한이 제대로 동작하는 것을 확인할 수 있습니다.

5. 온라인 UI와 방 만들기 UI 연결

마지막으로 완성된 방 만들기 UI를 온라인 UI와 연결시키겠습니다. 이 부분은 앞 포스트의 작업과 동일하므로 간단히 작성만 하고 넘어가겠습니다.

Create Room UI의 cancel 버튼의 On click()
Create Room UI 와 Online UI를 각각 추가한 후 Game Object / Set Active에서 Online UI를 체크

앞선 포스트와 한 가지 차이가 있다면 Online UI에서 방 만들기 UI로 넘어올 때 위의 닉네임 필드가 비어 있는 경우 넘어가지 못하게 해야합니다. 먼저 닉네임 필드를 입력하지 않았을 때 닉네임 필드를 흔드는 효과를 주고자 애니메이션을 만들겠습니다. (ctrl+6) 애니메이션의 경우 녹화 버튼을 눌려 왼쪽 -> 중간 -> 오른쪽 -> 중간 식으로 키 프레임을 잡아서 만들어 줍니다. (이 부분의 경우 플래피 버드 프로젝트에서 유사하게 다루었기에 넘어가겠습니다.)
https://velog.io/@dohui/Flappy-Bird-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EA%B8%B0%EB%B3%B8-%EC%9A%A9%EC%96%B4-%EC%A0%95%EB%A6%AC-%EB%B0%8F-UI-%EA%B5%AC%EC%84%B1-3

프로젝트 뷰를 눌러 흔들리는 효과를 한 번만 적용하기 위해 해당 애니메이션의 Loop Time을 비활성화 시킵니다.

다음으로 Hierarchy view에서 InputField의 Animation Controller를 선택한 다음 다음과 같이 설정합니다.

  1. On Trigger 생성
  2. Create Empty State (이름 None)
  3. None에서 Make transition을 하여 애니메이션과 연결 후 해당 transition을 선택하여 하단의 3번과 같이 설정 (Conditions에 on 설정)
  4. 애니메이션에서 Exit으로 transition 생성 후 하단의 4번과 같이 설정

마지막으로 스크립트를 작성합니다. 사용자의 닉네임을 담아둘 곳이 필요한데, 이전에 정의하였던 PlayerSettings 부분에 nickname 변수를 추가로 선언해줍니다.

public class PlayerSettings
{
    public static EcontrolType controlType;
    public static string nickname;

}

다음으로 OnlineUI 스크립트를 생성하여 다음 내용을 작성합니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; // 선언

public class OnlineUI : MonoBehaviour
{
    [SerializeField]
    private InputField nicknameInputField;
    [SerializeField]
    private GameObject createRoomUI;

    public void OnClickCreateRoomButton(){
        if(nicknameInputField.text != ""){ // 닉네임 필드가 비어있지 않는 경우에만 
        // 방만들기로 넘어감
            PlayerSettings.nickname = nicknameInputField.text; // input으로 받은 닉네임을 PlayerSettings에 저장
            createRoomUI.SetActive(true);
            gameObject.SetActive(false);
        }
        else{
            nicknameInputField.GetComponent<Animator>().SetTrigger("on"); // 입력 강조 애니메이션 실행
        }
    }
}

스크립트 작성을 마친 후 Online UI 오브젝트에 생성한 스크립트를 컴포넌트로 붙이고 각 property에 필요한 object들을 할당합니다.

InputField, CreateRoomUI

다음으로 hierarchy view에서 Online UI / Host / Button의 On Click()에 Online UI를 넣은 후 OnClickCreateRoomButton 함수를 등록합니다.

최종적으로 방 UI 구현이 끝난 결과입니다.

profile
하나씩 심어 나가는 개발 농장🥕 (블로그 이전중)

0개의 댓글

관련 채용 정보