Kohandage ekraanil kuvatavat juhtelementi D-padi rakendamiseks

Lehekülg uuendatud :
Lehe loomise kuupäev :

Kontrollimise keskkond

Windows
  • Windows 11
Ühtsuse toimetaja
  • 2020.3.25f1
Sisendsüsteemi pakett
  • 1.2.0

Selle näpunäite eeltingimused

Selle vihje kirjeldamise eelduseks on eelnevalt tehtud järgmised sätted.

Samuti peaksite olema tuttav järgmiste nõuandetega:

Ekraanil olev juhtpult on standardne orientatsioonitoiming

On-Screen Stick on rakendatud virtuaalse pulgana, kopeerides pulga tööd, mis sarnaneb füüsilisel kontrolleril leiduvaga. Näiteks kui soovite seda paremale liigutada, võite kõigepealt puudutada ekraani, et puudutada keppi, ja seejärel libistada seda paremale, et kepp maha lüüa.

Seda on lihtne ette kujutada pulgaoperatsioonina, kuid vastupidi, kui soovite seda kohe paremale liigutada, (1) puudutage, (2) libistage paremale, Kuna see nõuab kaheastmelist operatsiooni, on vastus paratamatult veidi edasi lükatud. See kehtib eriti siis, kui peate järjest kiiresti suunda muutma.

D-pad, mis määrab suuna puudutamise hetkel (mittestandardsed)

Parim sisestusmeetod kiireks suunasisendiks on selline, mis suudab määrata suuna puudutamise hetkel, asetades midagi sellist nagu D-pad või nooleklahv. Seda ei tee Unity, kuid oma mängus Little Saber asetan nooleklahvid nii, et saaksite kiiresti liikuda puudutatavas suunas. Muidugi saate liigutuste vahetamiseks ka puudutades üles või vasakule libistada.

On-Screen Control standardit pole aga lihtne paigutada ja rakendada, kuna seal on ainult ekraanipulgad ja ekraanil olevad nupud.

Samuti saate luua pseudo-D-padja, korraldades neli nuppu, nagu on näidatud alloleval joonisel, kuid see on ebamugav, kuna te ei saa diagonaalselt sisestada. Kui asetate 8 nuppu, on diagonaalne töö võimalik, kuid voolusuuna toimimine, näiteks "← ↙ ↓", pole endiselt võimalik.

Suunapadja loomine ekraani juhtimise kohandamisega

Nagu näete, on ekraanil juhtimine standardvarustuses ainult pulga ja nupuga, kuid puuduvaid funktsioone saate kohandada oma skriptidega. Nii et siin tahaksin luua suunapadja, millel on ekraanil juhtimise kohandamine.

Tegevuskava

Kasutame tegevuskaarti, kuid kasutame eelmistes näpunäidetes loodud kaarti sellisena, nagu see on, nii et protseduur jäetakse välja.

Olete kirjutanud ka mõne koodi.

Objektide paigutamine

Sisestage sisendi kuvamiseks tekstiala ja nupp, mis asendab D-padi. Sellisel juhul on nupud paigutatud, kuid saate need asendada pildiga, mida on lihtsam mõista.

Skript sisendi kuvamiseks

Kuna ekraanil juhtimine asendab puutetundliku füüsilise kontrolleri interaktsiooniga, Looge skript, mis kuvab teie sisendi tekstina, kui tegevuskaart töötab.

Sisu on sama, mis varem, nii et jätan selgituse välja.

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}";
  }
}

Pärast selle seadistamist kontrollige kõigepealt, kas see töötab klaviatuuri või mängupuldiga.

Ekraanil kuvatavate juhtelementide kohandamine

See toob meid nende näpunäidete põhiteema juurde. Ekraanil kuvatava juhtelemendi kohandamine on skript, nii et kõigepealt looge skript. Nimi on meelevaldne, kuid sel juhul OnScreenDpad on see .

Skript näeb välja selline:

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);
  }
}

Ekraanil kuvatava juhtimise kohandamisklassi loomiseks OnScreenControl pärite klassist Kohandamine. Lisaks pärige erinevate puutesündmuste vastuvõtmiseks sihtliides. Siin töödeldakse "puudutamisel", "puudutamise ajal liikudes", "kui puudutus vabastatakse" ja "enne lohistamist", seega kirjeldatakse vastavalt ka järgmisi liideseid.

public class OnScreenDpad
  : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Liidese sisu
IPointerDownHandler Kui puudutatakse
IPointerUpHandler Kui vabastate puudutuse
IDragHandler Kui liigute puudutamise ajal
IInitializePotentialDragHandler Enne lohistamise alustamist

Deklareeritakse järgmised väljad:

controlPathInternalOnScreenControl on nõutav, kui pärite klassist. See hoiab stringi, millise sisendseadme nupuga kaardistada, kuid põhimõtteliselt saate selle kirjutada nii, nagu see on. InputControl Atribuut peaks siiski sisaldama säilitatavat väärtust (antud juhul vektor2).

_objectPosition_objectSizeHalf ja hoidke eelnevalt pool nupu asukohast ja suurusest ning kasutage seda hiljem arvutusteks.

[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;

Meetod, mida nimetatakse Start pärast objekti lähtestamist, saab poole lõuendil oleva nupu asukohast ja suurusest. Suurus võtab arvesse ka skaala. Start Seda töödeldakse meetodiga, kuid kui seda saab lõpuks arvutuses õigesti kasutada, võib omandamise ajastus olla ükskõik kus.

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

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

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

OnInitializePotentialDrag helistatakse, kui soovite pärast puudutust lohistamist alustada. Lohistamise OnDrag ajal nimetatakse meetodit. Lävi on seatud selleks, et takistada mingil määral lohistamisotsust, nii et sõrm ei liiguks vähe ja tõmbeotsust ei tehtaks lihtsalt puudutamise tõttu.

Seekord, kuna see on sisend, mis eeldab, et soovite peenhäälestustoimingut teha, keelake see läve seadistus ja tehke kohe lohistamisotsus. eventData.useDragThreshold false Saate läve alistada, seades väärtuseks .

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

Allpool on toodud sündmused, mida nimetatakse vastavalt puudutamisel, lohistamisel ja vabastamisel. OnPointerDown OnDrag Kuna ja , igaüks täidab Operate sama sisendtöötlust, siis loome eraldi meetodi ja nimetame seda. OnPointerUp Nüüd edastage see meetodile, et teavitada juhtelementi, et SendValueToControl Vector2.zero see on tippimise lõpetanud.

/// <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 Meetod on peamine D-pad sisendoperatsioon.

Kõigepealt saab puutetundliku positsiooni , kuid kuna see koordinaat on mänguekraani koordinaat eventData.position , RectTransformUtility.ScreenPointToLocalPointInRectangle lõuendi koordinaatideks teisendamise meetod. Edastatavad väärtused on "lõuend", "puuteasend", "kaamera" ja "vastuvõttev muutuja" RectTransform.

Pärast "puutetundliku positsiooni lõuendil" saamist teisendage see nupu asendisse kui päritolu. Lihtsalt lahutage objekti asukoht ()._objectPosition

Järgmisena, kuna puuteasend on lõuendil endiselt number, teisendage see väärtus suhteks 0 ~ 1. Kui jagate poole nupu suurusest, on puuteasend nupu vahemikus 0 ~ 1. Kui lohistate puutesiseselt, on väärtus 1 või rohkem, kuna see aktsepteerib toiminguid isegi väljaspool nuppu. Vector2.ClampMagnitude Tehke seda meetodis nii, et see ei ületaks 1.

Lõpuks edastage meetodile sisendväärtus SendValueToControl , mis on teisendatud väärtuseks 0 ~ 1. Ekraanil kuvatav juhtelement teeb ülejäänu teie eest.

/// <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);
}

Manustage loodud skript nupule. Seda toimingut käsitletakse mängupuldi vasaku pulga toimimisena.

Proovige mängu liigutada ja puudutage nuppe. Ma arvan, et näete, et saadud väärtus muutub sõltuvalt puuteasendist. Samuti näete, et isegi kui lohistate puudutamise ajal, muutub väärtus sõltuvalt lohistamise asendist.