본문 바로가기

C#,Unity

스크립트로 UI 제어하기 - Selectable

 

Unity에서 사용할 수 있는 UI들을 마우스뿐만이 아니라 키보드로 조작할 수도 있다는 사실은 여간 신기한 정보가 아닐 수가 없습니다.

 

그러나 대부분의 게임은 플레이 도중 원치 않게 UI를 조작하는 것을 방지하기 위해 Navigation을 None으로 설정해 키보드 조작을 막아놓는 경우가 많을 것입니다.

 

사실 본인은 게임 하나밖에 안 만들어봐서 보편적인 경험이라고 비약시키긴 힘들겠네요.

 

 

일반적으로 UI를 클릭하면 해당 UI는 Click 이벤트가 실행된 다음 Select 상태로 남습니다.

UI의 Transition 정보에서 그것을 유추할 수 있습니다.

 

이 상태에서 해당 UI의 Navigation이 활성화되어 있다면 상하좌우+스페이스바/엔터 키코드로 주변 UI로 넘어가거나 클릭 없이 클릭 이벤트를 발동시킬 수 있습니다.

 

다만 이러한 상태에서 UI 외 배경 화면을 한번이라도 클릭하면 Normal 상태로 넘어가고, 더 이상 키보드로 UI를 조작하지 못하게 됩니다.

 

마우스 클릭으로 UI 조작 -> 마우스/키보드 UI 조작 -> 마우스 클릭으로 UI 조작 나가기, 이와 같은 과정이 기본적으로 유니티에서 사용할 수 있는 UI 조작 시스템입니다.

 

 

그러나 UI의 Button 등등 기타 대부분 UI가 상속받고 있는 'Selectable' 클래스를 활용한다면 오로지 키보드만을 사용해 UI를 조작할 수 있습니다.

public class test : MonoBehaviour
{
  [SerializeField] private TextMeshProUGUI MyText = null;
  [SerializeField] private TextMeshProUGUI MyText_control = null;
  [SerializeField] private List<Selectable> MySelects = null;     
  [SerializeField] EventSystem MyEventSystem = null;
  private GameObject CurrentSelectable = null; //UI 조작 상태에서 나간 후 마지막으로 선택한 UI를 담는 변수

  Dictionary<KeyCode, Action> KeyCodeActions = new Dictionary<KeyCode, Action>();
  private void Awake()
  {
    KeyCodeActions.Add(KeyCode.LeftArrow, () => MyText_control.text += "<br>" + "Left");
    KeyCodeActions.Add(KeyCode.RightArrow, () => MyText_control.text += "<br>" + "Right");
    KeyCodeActions.Add(KeyCode.UpArrow, () => MyText_control.text += "<br>" + "Up");
    KeyCodeActions.Add(KeyCode.DownArrow, () => MyText_control.text += "<br>" + "Down");
    KeyCodeActions.Add(KeyCode.Backspace, () => 
    { CurrentSelectable = MyEventSystem.currentSelectedGameObject;
      MyEventSystem.SetSelectedGameObject(null);
    });
    //키코드,액션을 딕셔너리화시켜 Input.getkeydown(Keycode)를 더 보기 좋게 활용
  }

  private void Update()
  {
    foreach (var _dic in KeyCodeActions)
      if (Input.GetKeyDown(_dic.Key))
      {
        //EventSystem.currentSelectedGameObject: 현재 Select된 게임오브젝트
        if (MyEventSystem.currentSelectedGameObject == null)  //현재 EventSystem에서 Select된 UI가 없을 시
        {
          if (CurrentSelectable == null) MySelects[0].Select();//기존 선택 UI가 없다면 적당한 첫번째 UI로 시작
          else CurrentSelectable.GetComponent<Selectable>().Select();//아니라면 마지막으로 조작한 UI를 Select
        }
        _dic.Value();//키코드에 할당된 메소드 실행
      }
  }

  public void Lehu(GameObject obj)  //텍스트 출력용 메소드
  {
    MyText.text += "<br>" + obj.name.ToString();
  }
}

EventSystem.SetSelectedGameObject(null) => 선택중인 오브젝트를 비활성화하기

(걍 허공에 클릭하는것과 같은 기능)

EventSystem.currentSelectedGameObject => 선택중인 오브젝트(Select 상태인 오브젝트)

Selectable.Select() => 클릭 이벤트가 없는 클릭 기능

 

 

 

 

사실 그닥 거창한 내용은 아니었습니다만 모르고 있는 것보단 낫지요.