Prilagajanje nadzora na zaslonu za izvedbo tipkovnice D-pad

Stran posodobljena :
Datum ustvarjanja strani :

Okolje za preverjanje

Windows
  • Windows 11
Urejevalnik Unity
  • 2020.3.25F1
Paket vhodnega sistema
  • 1.2.0

Predpogoji za ta nasvet

Naslednje nastavitve so bile vnaprej narejene kot premisa za opis tega nasveta.

Prav tako morate poznati naslednje nasvete:

Kontrolna tipka na zaslonu je standardna orientacijska operacija

On-Screen Stick je implementiran kot virtualna palica, ki posnema delovanje palice, podobno tistemu, ki ga najdemo na fizičnem krmilniku. Če ga želite na primer premakniti v desno, se lahko najprej dotaknete zaslona, da se dotaknete palice, nato pa ga potisnete v desno, da palico potisnete navzdol.

To si je lahko predstavljati kot operacijo palice, ampak nasprotno, ko jo želite takoj premakniti v desno, (1) dotik, (2) potisnite v desno, Ker zahteva dvostopenjsko operacijo, bo odziv neizogibno nekoliko zakasnjen. To še posebej velja, če morate hitro spremeniti smer zapored.

D-pad, ki določa smer v trenutku dotika (nestandardno)

Najboljša vhodna metoda za hiter vnos smeri je tista, ki lahko določi smer v trenutku dotika tako, da postavi nekaj podobnega D-padu ali puščični tipki. Ni ga naredil Unity, ampak v moji igri Little Saber, postavim puščične tipke, tako da se lahko hitro premaknete v smeri, ki se je dotaknete. Seveda lahko med dotikanjem tudi drsite navzgor ali levo, da preklopite med premikanjem.

Vendar pa standarda On-Screen Control ni enostavno namestiti in izvajati, ker obstajajo samo zaslonske palice in gumbi na zaslonu.

Psevdo-D-pad lahko ustvarite tudi tako, da razporedite štiri gumbe, kot je prikazano na spodnji sliki, vendar je neprijetno, ker ne morete vnesti diagonalno. Če postavite 8 gumbov, je diagonalno delovanje možno, vendar delovanje smeri pretoka, kot je "← ↙ ↓", še vedno ni mogoče.

Ustvarjanje smerne ploščice s prilagajanjem funkcije On-Screen Control

Kot lahko vidite, je nadzor na zaslonu standarden samo s palico in gumbom, manjkajoče funkcije pa lahko prilagodite s svojimi skripti. Torej, tukaj bi rad ustvaril smerno ploščico s prilagajanjem nadzora zaslona.

Zemljevid dejanj

Uporabili bomo akcijski zemljevid, vendar bomo uporabili tistega, ustvarjenega v prejšnjih nasvetih, kot je, zato je postopek izpuščen.

Napisali ste tudi nekaj kode.

Pozicioniranje predmetov

Postavite območje besedila za prikaz vnosa in gumb, ki nadomešča tipkovnico D-pad. V tem primeru so gumbi razporejeni, vendar jih lahko zamenjate s sliko, ki je lažje razumljiva.

Skript za prikaz vnosa

Ker nadzor na zaslonu nadomešča dotik s fizično interakcijo krmilnika, Ustvarite skript, ki prikaže vaš vnos v besedilu med delovanjem zemljevida dejanj.

Vsebina je enaka kot prej, zato bom pojasnilo izpustil.

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class InputActionScript : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  /// <summary>アクションマップから自動生成されたクラス。</summary>
  private InputActionSample _actionMap;

  private void Awake()
  {
    // 各操作を行ったときに呼ばれるイベントを設定する
    _actionMap = new InputActionSample();
    _actionMap.Action2D.Move.performed += context => OnMove(context);
    _actionMap.Action2D.Attack.performed += context => OnAttack(context);
    _actionMap.Action2D.Move.canceled += context => OnMove(context);
    _actionMap.Action2D.Attack.canceled += context => OnAttack(context);
  }

  private void OnEnable()
  {
    // このオブジェクトが有効になったときにアクションマップを有効にする
    _actionMap.Enable();
  }

  private void OnDisable()
  {
    // このオブジェクトが無効になったときにアクションマップが余計な動作を起こさないように無効にする
    _actionMap.Disable();
  }

  /// <summary>
  /// Move 操作をした時に呼ばれるメソッドです。
  /// </summary>
  /// <param name="context">コールバックパラメータ。</param>
  public void OnMove(InputAction.CallbackContext context)
  {
    // Move の入力量を取得
    var vec = context.ReadValue<Vector2>();
    TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
  }

  /// <summary>
  /// Attack 操作をした時に呼ばれるメソッドです。
  /// </summary>
  /// <param name="context">コールバックパラメータ。</param>
  public void OnAttack(InputAction.CallbackContext context)
  {
    // Attack ボタンの状態を取得
    var value = context.ReadValueAsButton();
    TextObject.text = $"Attack:{value}\n{TextObject.text}";
  }
}

Ko ga nastavite, najprej preverite, ali deluje s tipkovnico ali igralno konzolo.

Prilagajanje kontrolnikov na zaslonu

To nas pripelje do glavne teme teh nasvetov. Prilagajanje kontrolnika na zaslonu je skript, zato najprej ustvarite skript. Ime je poljubno, vendar je v tem primeru OnScreenDpad .

Scenarij izgleda takole:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.OnScreen;

public class OnScreenDpad
  : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
{
  [InputControl(layout = "Vector2")]
  [SerializeField]
  private string _controlPath;
  /// <summary><see cref="OnScreenControl"/> で定義された値。</summary>
  protected override string controlPathInternal { get => _controlPath; set => _controlPath = value; }

  /// <summary>オブジェクトの位置。</summary>
  private Vector2 _objectPosition;

  /// <summary>オブジェクトのサイズの半分 (スケールも含む)。</summary>
  private Vector2 _objectSizeHalf;


  /// <summary>
  /// オブジェクトが動作する最初のタイミングで1回だけ呼ばれます。
  /// </summary>
  private void Start()
  {
    var rectTransform = (RectTransform)base.transform;

    // オブジェクトの位置を取得
    _objectPosition = rectTransform.anchoredPosition;

    // オブジェクトのサイズの半分を取得 (スケールサイズも考慮)
    _objectSizeHalf = rectTransform.sizeDelta * rectTransform.localScale / 2f;
  }

  /// <summary>ドラッグの初期化処理として呼ばれます。</summary>
  /// <param name="eventData">タッチ情報。</param>
  public void OnInitializePotentialDrag(PointerEventData eventData)
  {
    // タッチのスライド操作を即座に発生させたいのでドラッグ開始までの閾値を無効にします
    eventData.useDragThreshold = false;
  }

  /// <summary>タッチしたタイミングで呼ばれます。</summary>
  /// <param name="eventData">タッチ情報。</param>
  public void OnPointerDown(PointerEventData eventData)
  {
    Operate(eventData);
  }

  /// <summary>タッチした後ドラッグするたびに呼ばれます。</summary>
  /// <param name="eventData">タッチ情報。</param>
  public void OnDrag(PointerEventData eventData)
  {
    Operate(eventData);
  }

  /// <summary>タッチを離したときに呼ばれます。</summary>
  /// <param name="eventData">タッチ情報。</param>
  public void OnPointerUp(PointerEventData eventData)
  {
    // 入力をやめた扱いにしたいので zero を渡します
    SendValueToControl(Vector2.zero);
  }

  /// <summary>
  /// 方向パッドの入力処理を行います。
  /// </summary>
  /// <param name="eventData">タッチ情報。</param>
  private void Operate(PointerEventData eventData)
  {
    // タッチ位置を Canvas 上の位置に変換します
    RectTransformUtility.ScreenPointToLocalPointInRectangle(
      transform.parent.GetComponentInParent<RectTransform>(),
      eventData.position,
      eventData.pressEventCamera,
      out Vector2 localPoint);

    // Dpad の中心を原点としたタッチ位置
    Vector2 positionInDpad = localPoint - _objectPosition;

    // タッチ位置をオブジェクトサイズの半分で割り 0~1 の範囲に収めます
    Vector2 positionRate = Vector2.ClampMagnitude(positionInDpad / _objectSizeHalf, 1);

    // 入力値を OnScreenControl に渡してその後の処理を任せます。
    SendValueToControl(positionRate);
  }
}

Razred prilagajanja kontrolnika na zaslonu OnScreenControl ustvarite tako, da dedujete iz razreda Prilagodi. Poleg tega za prejemanje različnih dogodkov na dotik podedujte ciljni vmesnik. Tu se obdelujejo "pri dotikanju", "pri premikanju med dotikom", "ko se dotik sprosti" in "pred vlečenjem", zato so opisani tudi naslednji vmesniki.

public class OnScreenDpad
  : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Vsebina vmesnika
IPointerDownHandler Ob dotiku
IPointerUpHandler Ko spustite dotik
IDragHandler Ko se premikate med dotikom
IInitializePotentialDragHandler Preden začnete vleči

Navedena so naslednja polja:

controlPathInternalOnScreenControl je potrebno, če dedujete od razreda. Vsebuje niz, na kateri gumb vhodne naprave želite preslikati, v bistvu pa ga lahko zapišete takšnega, kot je. InputControl Vendar mora atribut vsebovati vrednost, ki jo je treba obdržati (v tem primeru Vector2).

_objectPosition_objectSizeHalf in vnaprej držite polovico položaja in velikosti gumba in ga pozneje uporabite za izračune.

[InputControl(layout = "Vector2")]
[SerializeField]
private string _controlPath;
/// <summary><see cref="OnScreenControl"/> で定義された値。</summary>
protected override string controlPathInternal { get => _controlPath; set => _controlPath = value; }

/// <summary>オブジェクトの位置。</summary>
private Vector2 _objectPosition;

/// <summary>オブジェクトのサイズの半分 (スケールも含む)。</summary>
private Vector2 _objectSizeHalf;

Metoda, imenovana Start po inicializaciji predmeta, dobi polovico položaja in velikosti gumba na platnu. Velikost upošteva tudi lestvico. Start Obdeluje se z metodo, če pa jo je na koncu mogoče pravilno uporabiti pri izračunu, je lahko čas pridobitve kjerkoli.

// <summary>
// オブジェクトが動作する最初のタイミングで1回だけ呼ばれます。
// </summary>
private void Start()
{
  var rectTransform = (RectTransform)base.transform;

  // オブジェクトの位置を取得
  _objectPosition = rectTransform.anchoredPosition;

  // オブジェクトのサイズの半分を取得 (スケールサイズも考慮)
  _objectSizeHalf = rectTransform.sizeDelta * rectTransform.localScale / 2f;
}

OnInitializePotentialDrag se pokliče, ko želite začeti vleči po dotiku. Med vlečenjem se metoda imenuje. OnDrag Nastavljen je prag, ki do neke mere preprečuje presojo vlečenja, tako da se prst ne premakne malo in se sodba vlečenja ne pojavi zaradi operacije preprostega dotikanja.

Tokrat, ker gre za vhod, ki predvideva, da želite izvesti postopek natančne nastavitve, onemogočite to nastavitev praga in takoj naredite presojo povleci. eventData.useDragThreshold false Prag lahko preglasite tako, da nastavite na .

/// <summary>ドラッグの初期化処理として呼ばれます。</summary>
/// <param name="eventData">タッチ情報。</param>
public void OnInitializePotentialDrag(PointerEventData eventData)
{
  // タッチのスライド操作を即座に発生させたいのでドラッグ開始までの閾値を無効にします
  eventData.useDragThreshold = false;
}

Spodaj so navedeni dogodki, imenovani ob dotiku, vlečenju in sproščanju. OnPointerDown OnDrag Ker in , vsak izvaja Operate enako vhodno obdelavo, zato ustvarimo ločeno metodo in jo pokličemo. OnPointerUp Zdaj ga posredujte metodi, da kontrolnik obvestite, da SendValueToControl Vector2.zero je prenehal tipkati.

/// <summary>タッチしたタイミングで呼ばれます。</summary>
/// <param name="eventData">タッチ情報。</param>
public void OnPointerDown(PointerEventData eventData)
{
  Operate(eventData);
}

/// <summary>タッチした後ドラッグするたびに呼ばれます。</summary>
/// <param name="eventData">タッチ情報。</param>
public void OnDrag(PointerEventData eventData)
{
  Operate(eventData);
}

/// <summary>タッチを離したときに呼ばれます。</summary>
/// <param name="eventData">タッチ情報。</param>
public void OnPointerUp(PointerEventData eventData)
{
  // 入力をやめた扱いにしたいので zero を渡します
  SendValueToControl(Vector2.zero);
}

Operate Metoda je jedro D-pad vhodne operacije.

Najprej je mogoče dobiti položaj na dotik z , ker pa je ta koordinata koordinata eventData.position zaslona igre, RectTransformUtility.ScreenPointToLocalPointInRectangle Metoda za pretvorbo v koordinate platna. Vrednosti, ki jih je treba posredovati, so "platno", "položaj na dotik", "kamera" in " RectTransformsprejemna spremenljivka".

Ko dobite "položaj na dotik na platnu", ga pretvorite v položaj gumba kot izvor. Samo odštejte položaj () predmeta_objectPosition.

Nato, ker je položaj na dotik še vedno številka na platnu, pretvorite to vrednost v razmerje 0 ~ 1. Če delite polovico velikosti gumba, bo položaj dotika v območju gumba 0 ~ 1. Če vlečete z dotikom, bo vrednost 1 ali več, ker sprejema postopke tudi zunaj gumba. Vector2.ClampMagnitude To storite v metodi, tako da ne presega 1.

Na koncu prenesite vhodno vrednost SendValueToControl , pretvorjeno v 0 ~ 1, v metodo. Nadzor na zaslonu naredi vse ostalo namesto vas.

/// <summary>
/// 方向パッドの入力処理を行います。
/// </summary>
/// <param name="eventData">タッチ情報。</param>
private void Operate(PointerEventData eventData)
{
  // タッチ位置を Canvas 上の位置に変換します
  RectTransformUtility.ScreenPointToLocalPointInRectangle(
    transform.parent.GetComponentInParent<RectTransform>(),
    eventData.position,
    eventData.pressEventCamera,
    out Vector2 localPoint);

  // Dpad の中心を原点としたタッチ位置
  Vector2 positionInDpad = localPoint - _objectPosition;

  // タッチ位置をオブジェクトサイズの半分で割り 0~1 の範囲に収めます
  Vector2 positionRate = Vector2.ClampMagnitude(positionInDpad / _objectSizeHalf, 1);

  // 入力値を OnScreenControl に渡してその後の処理を任せます。
  SendValueToControl(positionRate);
}

Na gumb priložite skript, ki ste ga ustvarili. To dejanje bo obravnavano kot delovanje leve palice igralne konzole.

Poskusite premakniti igro in se dotaknite gumbov. Mislim, da lahko vidite, da se dobljena vrednost spreminja glede na položaj dotika. Prav tako lahko vidite, da se vrednost, tudi če povlečete med dotikom, spreminja glede na položaj povleci.