[Toy/Unity] 상호작용 개선.. 및 이것저것

0시0분·2024년 6월 18일
0

Toy

목록 보기
10/18

예전에 한번 정리한답시고 글을 썼던 적이 있는데
간만에 다시 작업을 하려니 내 스스로도 헷갈리는 네이밍과 구조로 되어 있어서 싹 갈아 엎었다.

당시엔 이것저것 많이 넣어보려고 먼저 틀을 잡았었는데,
역시 나는 하나씩 해보면서 구조를 짜는게 맞는 것 같다..


1. 상호작용 가능한 오브젝트 클릭시

클릭 위치로 이동하는 기능을 구현하고 나니, 오브젝트를 클릭했을 때는 어떻게 처리해야 할지 고민이 됐다.

1. 아무것도 하지 않기 (근처까지 이동해야 동작하도록)
2. 해당 위치로 이동하기
3. 이동하기 + 상호작용 실행하기

유저의 의도는 보통 3번이겠지만..
로직이 너무 복잡해질 것 같아서 간단한 2번으로 가기로 했다.

목적지를 설정하는 부분에

if (GetMapPos(endPos).isInteractable)   endPos.y += -1;

클릭한 위치가 isInteractable하면 (=상호작용 가능하면) 오브젝트의 한칸 아래 타일로 이동하도록 했다.

2. 오브젝트와 상호작용

오브젝트 구조는 당장 구현에 필요한 두가지로 축약해서 정리했다.
타일맵 위에 올라가는 오브젝트는 모두 BaseObject를 부모로 가지며, 그 중 캐비닛은 인벤토리 UI를 오픈하는 UIObject이다.

private void Interact()
{
	// ✏️ 상호작용 키는 '마우스 우클릭'
    if (m_inputKey != KeyCode.Mouse1)   return;

    Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    Node cellNode = MapManager.Inst.GetMapPos(mousePos);

	// ✏️ 클릭한 위치가 상호작용 가능하지 않을 경우 return
    if (cellNode.isInteractable == false) return;
    // ✏️ 현재 플레이어의 위치가 클릭한 오브젝트 근처가 아닐 경우 (기준 값 1.5f)
    if (MapManager.Inst.IsNearBy(new Vector3(cellNode.x, cellNode.y), transform.position) == false) return;

	// ✏️ 클릭한 위치 타일 검사 -> 상호작용 함수 호출
    Collider2D col = Physics2D.OverlapCircle(mousePos, 0.4f, LayerMask.GetMask(ClientUtil.InteractableLayer));
    if (col != null)
    {
        if (col.TryGetComponent(out BaseObject baseComp) == false)     return;
        baseComp.I_InteractableFunc();
    }
}

3. UI 구조

기본 UI와 그를 상속받는 인벤토리 UI 로 단순하게 변경했다.

UIObject는 BaseUI 클래스를 변수로 가지고 있고,
상호작용 버튼이 클릭되면 UIManager에 해당 값을 넘긴다.

UIManager.Inst.OpenUI(m_ui);

바로 오픈하지 않고 매니저로 넘긴 이유는 크게 두가지가 있다.

  1. UI가 켜져있는 동안 이동 불가능하게 처리하기 위해 UI On/Off 여부를 관리할 필요성이 존재
  2. UI의 스택을 관리해서 Esc 키로 상위 UI부터 닫는 기능을 구현하기 위해

꼭 위와 같은 이유가 아니더라도 UI 관련 기능은 한군데서 관리하는게 좋다.

// *** UI Open ***
// UIObject.cs
public override void I_InteractableFunc()
{
    UIManager.Inst.OpenUI(m_ui);
}

// UIManager.cs
public void OpenUI(BaseUI ui)
{
    isUIOpened = true;

    m_uiOpened.Add(ui);
    ui.Open();
}

// *** UI Close ***
// BaseUI.cs
public virtual void OnClickClose()
{
    UIManager.Inst.CloseUI(this);
}

// UIManager.cs
public void CloseUI(BaseUI ui)
{
    m_uiOpened.Remove(ui);
    ui.Close();

    if (m_uiOpened.Count == 0)
    {
        isUIOpened = false;
    }
}

다만 2번의 Esc 클릭시 닫는 기능은 키 입력이 씹히는 현상이 있어서 조금 더 확인해봐야 할 것 같다.

0개의 댓글