השארת המוקד מחוץ לאובייקט ממשק המשתמש

עודכן דף :
תאריך יצירת דף :

סביבת אימות

חלונות
  • חלונות 11
עורך Unity
  • 2020.3.25F1

תנאים מוקדמים לטיפ זה

ההגדרות הבאות נעשו מראש כתנאי מוקדם להסבר על טיפים אלה.

מה הועיל לך בטיפ הזה?

הסיפור המקורי היה איפשהו, אבל לא הצלחתי למצוא אותו על ידי חיפוש מילות מפתח.

אודות פוקוס

אובייקטי ממשק משתמש של Unity, כמו כל אפליקציה אחרת, יכולים להתמקד ולציין שהם פעילים כיעדי קלט. עם זאת, אם תלחץ או תיגע בכל אובייקט שאינו האובייקט, האובייקט שבו נמצא המוקד ייעלם. ייתכן שלא ניתן יהיה לקבל פעולות עם מקלדת או gamepad.

סעיף זה מתאר כיצד להשתמש בסקריפטים כדי לשלוט במוקד כך שלא יאבד את המיקוד בפסאודו. שים לב שתמיכה זו אינה תכונה של Unity ועלולה לגרום לך לאבד את המיקוד לרגע.

מיקום אובייקטים

סוג האובייקט אינו משנה בבקרת המיקוד, לכן מקם אותו בהתאם.

הוא צבוע כך שקל לראות שהוא בפוקוס.

לעת עתה, אם תפעילו אותו במצב זה, תוכלו לראות שאם תלחצו על מקום ריק לאחר שהאובייקט יקבל מיקוד, הוא יאבד את המיקוד.

שליטה כדי שלא תאבד מיקוד

לשם כך, צור סקריפט. שם הסקריפט יכול להיות כל דבר, אך FocusRequired השאר אותו כ- .

הזן את הקוד באופן הבא:

using System.Collections;
using System.Linq;                 // 追加
using UnityEngine;
using UnityEngine.EventSystems;    // 追加
using UnityEngine.UI;              // 追加

public class FocusRequired : MonoBehaviour
{
  /// <summary>
  /// <see cref="Selectable"/> をフックするクラスです。
  /// </summary>
  private class SelectionHooker : MonoBehaviour, IDeselectHandler
  {
    /// <summary>親コンポーネント。</summary>
    public FocusRequired Restrictor;

    /// <summary>
    /// 選択解除時にそれまで選択されていたオブジェクトを覚えておく。
    /// </summary>
    /// <param name="eventData"></param>
    public void OnDeselect(BaseEventData eventData)
    {
      Restrictor.PreviousSelection = eventData.selectedObject;
    }
  }

  /// <summary>選択させないオブジェクト一覧。</summary>
  [SerializeField] private GameObject[] NotSelectables;

  /// <summary>直前まで選択されていたオブジェクト。</summary>
  private GameObject PreviousSelection = null;

  /// <summary>
  /// 選択対象のオブジェクト一覧。
  /// </summary>
  private GameObject[] _selectables;

  private void Awake()
  {
    // すべての Selectable を取得する
    var selectableList = (FindObjectsOfType(typeof(Selectable)) as Selectable[]).ToList();

    // 選択除外がある場合は外す
    if (NotSelectables != null)
    {
      foreach (var item in NotSelectables)
      {
        var sel = item?.GetComponent<Selectable>();
        if (sel != null) selectableList.Remove(sel);
      }
    }

    _selectables = selectableList.Select(x => x.gameObject).ToArray();

    // フォーカス許可オブジェクトに SelectionHooker をアタッチ
    foreach (var selectable in this._selectables)
    {
      var hooker = selectable.AddComponent<SelectionHooker>();
      hooker.Restrictor = this;
    }

    // フォーカス制御用コルーチンをスタート
    StartCoroutine(RestrictSelection());
  }

  /// <summary>
  /// フォーカス制御処理。
  /// </summary>
  /// <returns></returns>
  private IEnumerator RestrictSelection()
  {
    while (true)
    {
      // 別なオブジェクトを選択するまで待機
      yield return new WaitUntil(
          () => (EventSystem.current != null) && (EventSystem.current.currentSelectedGameObject != PreviousSelection));

      // まだオブジェクトを未選択、または許可リストを選択しているなら何もしない
      if ((PreviousSelection == null) || _selectables.Contains(EventSystem.current.currentSelectedGameObject))
      {
        continue;
      }

      // 選択しているものがなくなった、または許可していない Selectable を選択した場合は前の選択に戻す
      EventSystem.current.SetSelectedGameObject(PreviousSelection);
    }
  }
}

אני לא אפרט יותר מדי, אבל מה שאני עושה הוא לשמור על אובייקט הבחירה הנוכחי, ואם "האובייקט שנבחר נעלם" או "בחרתי אובייקט שאיני מעוניין שייבחר", אני חוזר לבחירה הקודמת.

רכיב זה יכול להיות מחובר לכל אובייקט שקיים, אז EventSystem לצרף אותו ל- .

מכיוון שניתן לציין את האובייקט שאינך רוצה שייבחר כמאפיין, בוא ננסה להציב כפתור שאינך רוצה לבחור.

Not Selectables הלחצן מוגדר ל- .

נסה להפעיל אותו כדי לראות כיצד הוא פועל. ראשית, לחץ על אובייקט כדי לבחור אותו, ולאחר מכן לחץ על אזור ריק, כך שהוא לא לאבד את המיקוד.

ניתן גם לוודא שלחיצה על לחצן שהוגדר כלא נבחר לא תזיז את המיקוד.