# UI Navigation (不使用滑鼠來選擇 UI) 在 Unity 中,如果要使用上下左右 (i.e. 鍵盤、搖桿、D-pad)控制 UI,就必須要先設定 UI Navigation。 ## 手動啟用 先找到場景上的 Event System,設定好 First Select,也就是開啟場景時**第一個被選擇**的 UI 物件 (雖然這個欄位可以放所有 GameObject,但如果該 GameObject 不可以被選擇,視同沒有效果) ![](https://i.imgur.com/P5H4Dea.png) 同時,Unity 預設的顏色都很白、不容易被察覺。這裡我們把「被選中」顏色設的明顯一點 (<span style="color:#39C5BB">#39C5BB</span>)。 ![](https://i.imgur.com/bxwsiaa.png) 使用 Navigation 設定該物件可以透過上下、左右或是我全都要來選中; 點選 Visulaization 可以看到 UI 互動的流程圖。 ![](https://i.imgur.com/VYjfLoV.png) ## 自動化腳本 如果懶得設定上面那些東西,我寫了個小腳本可以動態變更場景上的可選擇物件,取名叫 `UiNavigationTweak` 然後拉進場景裡就可以了。 ```csharp= using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using UnityEngine.EventSystems; public class UiNavigationTweak : MonoBehaviour { void Start() { Refresh(); } public void Refresh() { var selectables = Transform.FindObjectsOfType<Selectable>(); var eventSystem = GameObject.FindObjectOfType<EventSystem>(); Color32 mikuColor = new Color32(0x39, 0xc5, 0xbb, 0xff); int i = 0; // mod all selected color foreach(var selectable in selectables) { var c = selectable.colors; c.selectedColor = mikuColor; selectable.colors = c; i++; } // evs if(i > 0 && eventSystem) { eventSystem.SetSelectedGameObject(selectables[0].gameObject); Debug.Log($"[UiNavigationTweak] Modded {i} objects."); } } } ``` :::info :::spoiler 如果專案會動態改變 UI,可以利用定期偵測這些變更把它套用 也可以由外部腳本呼叫 `Refresh()` ```csharp= using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using UnityEngine.EventSystems; public class UiNavigationTweak : MonoBehaviour { /// <summary> /// Start is called on the frame when a script is enabled just before /// any of the Update methods is called the first time. /// </summary> IEnumerator Start() { while(true) { Refresh(); yield return new WaitForSeconds(1); } } /// <summary> /// Start is called on the frame when a script is enabled just before /// any of the Update methods is called the first time. /// </summary> public void Refresh() { var selectables = Transform.FindObjectsOfType<Selectable>(); var eventSystem = GameObject.FindObjectOfType<EventSystem>(); Color32 mikuColor = new Color32(0x39, 0xc5, 0xbb, 0xff); int i = 0; // mod all selected color foreach(var selectable in selectables) { var c = selectable.colors; c.selectedColor = mikuColor; selectable.colors = c; i++; } // evs if(i > 0 && eventSystem) { Debug.Log($"[UiNavigationTweak] Modded {i} objects."); if(!eventSystem?.currentSelectedGameObject?.activeInHierarchy ?? true) eventSystem.SetSelectedGameObject(selectables[0].gameObject); } } } ``` :::