내일배움캠프/프로젝트

팀 프로젝트 - 로비 UI 디자인 변경

서보훈 2024. 12. 30. 20:45

로비 UI의 디자인을 변경하고, UI 활성화시 연출이 발생하도록 수정해주었습니다.

 

먼저 UI의 책을 넘기는 효과는 무료 에셋을 사용하여 구현해주었습니다.

https://assetstore.unity.com/packages/tools/animation/book-page-curl-55588

 

Book - Page Curl | 애니메이션 도구 | Unity Asset Store

Use the Book - Page Curl tool from Abdullah Aldandarawy on your next project. Find this & more animation tools on the Unity Asset Store.

assetstore.unity.com

 

해당 에셋의 Book.cs 에 추가적으로 FlipEvent 메서드를 만든 뒤, 해당 메서드를 Book 스크립트의 OnFlip 이벤트에 등록하여 책이 넘어가는 효과가 발생할때마다 메서드가 호출되도록 만들어주었습니다.

public void FlipEvent()
{
    switch (currentPage)
    {
        case 0:
            lobbyUi.loginUI.SetActive(true);
            break;
        case 2:
            lobbyUi.searchLobbyUI.SetActive(true);
            break;
        case 4:
            lobbyUi.lobbyUI.SetActive(true);
            break;
    }
}

메뉴에 직접적으로 표기되는 이미지는 넘어가는 효과에 자연스럽게 보일 수 있도록 이미지로 만들어주었습니다

※ 만약 해외출시등을 계획한다면, 리소스 폴더를 통해 리스트에 넣어주거나, TMP를 사용하여 OnFlip시에 변경되도록 만들어주는것이 좋아보일듯 합니다.

 

버튼을 눌러 특정 UI에서 이동할 때, 이벤트를 발생시켜 책을 넘기는 효과를 발생시키는 방식으로 만들어주었습니다.

//로비 UI의 책 넘기는 효과를 발생시키기 위한 이벤트
public event Action OnFlipRightEvent;
public event Action OnFlipLeftEvent;
public event Action<int> OnFlipToTargetEvent;

public void GameStartButtonControll(bool isActive)
{
    if (LobbyManager.Instance.IsLobbyhost() == false) return;
    StartButton.interactable = isActive;
}

public void CreateRoomButton()
{
    LobbyManager.Instance.CreateLobby(roomCodeInput.text);
    searchLobbyUI.SetActive(false);
    OnFlipRightEvent?.Invoke();
}

public void JoinRoomButton()
{
    LobbyManager.Instance.JoinLobbyByCode(roomCodeInput.text);
    searchLobbyUI.SetActive(false);
    OnFlipRightEvent?.Invoke();
}

public void LeaveLobbyButton()
{
    LobbyManager.Instance.LeaveLobby();
    OnFlipLeftEvent?.Invoke();
}
// Book.cs 에 추가적으로 사용하는 AutoFlip.cs
private void Awake()
{
    if (!ControledBook)
        ControledBook = GetComponent<Book>();

    ControledBook.lobbyUi.OnFlipToTargetEvent += StartTargetFlipCoroutine;
}

// Use this for initialization
void Start () {
    if (AutoStartFlip)
        StartFlipping();
    ControledBook.OnFlip.AddListener(new UnityEngine.Events.UnityAction(PageFlipped));

    NetworkAuthenticate.Instance.OnAuthenticateSuccessEvent += FlipRightPage;
    ControledBook.lobbyUi.OnFlipRightEvent += FlipRightPage;
    ControledBook.lobbyUi.OnFlipLeftEvent += FlipLeftPage;
}

 

UI를 활성화 할 때, 연출을 주기 위해 UIPopup 스크립트에서 전략을 정하고, 전략에 따라 활성화, 비활성화시 연출이 발생하도록 수정해주었습니다.

 

UI 기반은 팀원분이 작업하셨으며, 해당 기반에 제가 추가작업을 하였기때문에 UI기반에 대한 내용은 없습니다.

public class UIPopup : UIBase
{
    //팝업 UI 상속 클래스 (예: 인벤토리창 설정창)
    public UIMovementType movement;

    //UI 활성화, 비활성화시 전략
    private IPopupStrategy strategy;

    //전략패턴 지정
    private void Awake()
    {
        strategy = UIPopupFactory.SetPopupStrategy(gameObject, movement);
    }

    public override void Show()
    {
        base.Show();
        strategy.ShowUI();
    }

    public override void Hide()
    {
        base.Hide();
        strategy.HideUI();
    }
}

 

일단 페이드인, 아래에서 위로 슬라이드, 효과 없음 세가지의 전략패턴을 만들어주었습니다.

페이드인과 슬라이드 효과는 DOTween 을 사용하여 제작하였으며, 페이드인 연출의 경우 CanvasGroup 컴포넌트를 사용해야하기 때문에 해당 컴포넌트가 없으면 컴포넌트를 추가하도록 만들어주었습니다.

public enum UIMovementType
{
    None,
    Fade,
    SlideBottom
}

public interface IPopupStrategy
{
    public void ShowUI();
    public void HideUI();
}

//전략패턴 기반
public class UIStrategyBase
{
    protected GameObject ui;
    protected RectTransform transform;

    public UIStrategyBase(GameObject thisUi)
    {
        ui = thisUi;
        transform = ui.GetComponent<RectTransform>();
    }
}

//전략 : 아래에서 위로 슬라이드 하며 생성
public class UISlideBottomStrategy : UIStrategyBase, IPopupStrategy
{
    public UISlideBottomStrategy(GameObject ui) : base(ui)
    {
    }

    private Vector3 hideVector = new Vector3(960, -1080, 0);

    public void HideUI()
    {
        transform.position = Vector3.zero;
        CoroutineManager.Instance.StartMyCoroutine(ActiveUI(false));
    }

    public void ShowUI()
    {
        transform.position = hideVector;
        CoroutineManager.Instance.StartMyCoroutine(ActiveUI(true));
    }

    private IEnumerator ActiveUI(bool isActive)
    {
        if(isActive)
        {
            ui.SetActive(true);
            Tween tween = transform.DOAnchorPosY(0, 1f);
            yield return tween.WaitForCompletion();
        }
        else
        {
            Tween tween = transform.DOAnchorPosY(-1080, 1);
            yield return tween.WaitForCompletion();
            ui.SetActive(false);
        }
    }
}

//전략 : 페이드 인, 아웃
public class UIFadeStrategy : UIStrategyBase, IPopupStrategy
{
    private CanvasGroup canvasGroup;

    public UIFadeStrategy(GameObject ui) : base(ui)
    {
        if (!ui.TryGetComponent(out canvasGroup))
        {
            canvasGroup = ui.AddComponent<CanvasGroup>();
        }
    }

    public void HideUI()
    {
        CoroutineManager.Instance.StartMyCoroutine(Fade(true));
    }

    public void ShowUI()
    {
        CoroutineManager.Instance.StartMyCoroutine(Fade(false));
    }

    IEnumerator Fade(bool isFadeIn)
    {
        if(isFadeIn)
        {
            canvasGroup.alpha = 1f;
            Tween tween = canvasGroup.DOFade(0, 1);
            yield return tween.WaitForCompletion();
            ui.SetActive(false);
        }
        else
        {
            canvasGroup.alpha = 0f;
            ui.SetActive(true);
            Tween tween = canvasGroup.DOFade(1, 1);
            yield return tween.WaitForCompletion();
        }
    }
}

//전략 : 아무런 효과가 없음
public class UINoneStrategy : UIStrategyBase, IPopupStrategy
{
    public UINoneStrategy(GameObject ui) : base(ui)
    {
    }

    public void HideUI()
    {
        ui.SetActive(false);
    }

    public void ShowUI()
    {
        ui.SetActive(true);
    }
}

 

UI 생성시 전략은 팩토리 패턴을 통해 생성하며, UIPopup 스크립트의 Awake 문에서 Enum값을 기반으로 이 클래스를 통해 전략 객체를 만들어주는것을 볼 수 있습니다.

public static class UIPopupFactory
{
    // UI에 전략패턴을 만들어주는 팩토리 메서드
    public static IPopupStrategy SetPopupStrategy(GameObject ui, UIMovementType move)
    {
        IPopupStrategy strategy;

        switch (move)
        {
            case UIMovementType.None:
                strategy = new UINoneStrategy(ui);
                break;
            case UIMovementType.Fade:
                strategy = new UIFadeStrategy(ui);
                break;
            case UIMovementType.SlideBottom:
                strategy = new UISlideBottomStrategy(ui);
                break;
            default:
                strategy = new UINoneStrategy(ui);
                break;
        }

        return strategy;
    }
}

 

이번 작업에서는 트러블 슈팅 내용이 따로 존재하지 않습니다.

또한, 추가적인 UI 연출이 필요할경우, 전략을 늘리는 방식으로 대응하게될 것 같습니다.


해야할 일 목록

  • 게임 종료 버튼 구현
    • 까먹고있었습니다... 추가가 오래걸리는것은 아니기때문에 바로 만들어줄 것 같습니다.
  • 로비 뒷 배경 제작
    • 책상 오브젝트와 책 형태의 오브젝트를 비추는 형태로 만들어주면 될것이라고 생각하고 있습니다.
  • 추가 UI 제작
    • 조작법, 옵션 UI를 제작해주어야합니다.
    • 조작법은 이미지를 사용하게될 듯 하며, 옵션 UI의 경우 소리 설정등의 내용을 다루게될 것 같습니다.
    • 조작 키 변경도 추가하고 싶지만, 해당 내용을 다뤄본적이 없어서 최종적으로 추가할 내용이 없을때 제작을 시도해볼 것 같습니다.
  • 네트워크 예외 처리
    • 로그인시, 아무것도 입력하지 않으면 오류가 발생하지만, 그대로 다음 페이지에 넘어가는 현상을 발견하였습니다.
    • 이 외에도 네트워크 연결에 모두 예외처리를 해주는것이 좋다는 피드백을 받았기 때문에, 추가적인 예외처리를 진행해줄 예정입니다.