Mukauta näytön ohjaus suuntaohjaimen toteuttamiseksi

Sivu päivitetty :
Sivun luontipäivämäärä :

Varmennusympäristö

Windows
  • Windows 11
Unity-editori
  • 2020.3.25F1
Syöttöjärjestelmän paketti
  • 1.2.0

Tämän vinkin edellytykset

Seuraavat asetukset on tehty etukäteen tämän vinkin kuvauksen lähtökohtana.

Sinun tulisi myös tuntea seuraavat vinkit:

Näytön ohjaussauva on vakiosuuntatoiminto

On-Screen Stick on toteutettu virtuaalisena sauvana, joka toistaa samanlaisen sauvan toiminnan kuin fyysisessä ohjaimessa. Jos esimerkiksi haluat siirtää sitä oikealle, voit ensin koskettaa tikkua koskettamalla näyttöä ja liu'uttaa sitä sitten oikealle lyödäksesi sauvan alas.

Se on helppo kuvitella tikkuoperaatioksi, mutta päinvastoin, kun haluat siirtää sitä heti oikealle, (1) kosketa, (2) liu'uta oikealle, Koska se vaatii kaksivaiheista toimintaa, vastaus viivästyy väistämättä hieman. Tämä pätee erityisesti silloin, kun sinun on tehtävä nopea suunnanmuutos peräkkäin.

D-pad, joka määrittää suunnan kosketushetkellä (epätyypillinen)

Paras syöttötapa nopeaan suunnansyöttöön on sellainen, joka voi määrittää suunnan kosketushetkellä asettamalla jotain suuntaohjainta tai nuolinäppäintä. Se ei ole Unityn tekemä, mutta pelissäni Little Saber asetan nuolinäppäimet, jotta voit liikkua nopeasti koskettamaasi suuntaan. Voit tietysti myös liu'uttaa ylös tai vasemmalle koskettaessasi vaihtaaksesi liikkeitä.

On-Screen Control -standardia ei kuitenkaan ole helppo sijoittaa ja toteuttaa, koska siinä on vain näytön tikkuja ja näytön painikkeita.

Voit myös luoda pseudo-D-padin järjestämällä neljä painiketta alla olevan kuvan mukaisesti, mutta se on hankalaa, koska et voi syöttää vinosti. Jos asetat 8 painiketta, diagonaalinen toiminta on mahdollista, mutta virtaussuunnan käyttö, kuten "← ↙ ↓", ei silti ole mahdollista.

Luo suuntatyyny näytön ohjauksen mukauttamisella

Kuten näette, näytön ohjaus on vakiona vain sauvan ja painikkeen kanssa, mutta voit mukauttaa puuttuvia ominaisuuksia omilla skripteilläsi. Joten tässä haluaisin luoda suuntatyynyn, jossa on näytön ohjauksen mukauttaminen.

Toimintakartta

Käytämme toimintakarttaa, mutta käytämme edellisissä vinkeissä luotua sellaisenaan, joten menettely jätetään pois.

Olet myös kirjoittanut koodia.

Objektien sijoittaminen

Aseta tekstialue syötteen näyttämistä varten ja suuntaohjaimen korvaava painike. Tässä tapauksessa painikkeet on järjestetty, mutta voit korvata ne helpommin ymmärrettävällä kuvalla.

Komentosarja syötteen näyttämiseksi

Koska näytön hallinta korvaa kosketuksen ohjaimen fyysisellä vuorovaikutuksella, Luo komentosarja, joka näyttää syötteesi tekstinä, kun toimintokartta toimii.

Sisältö on sama kuin aiemmin, joten jätän selityksen pois.

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

Kun olet asentanut sen, tarkista ensin, toimiiko se näppäimistön tai peliohjaimen kanssa.

Näytön ohjausobjektien mukauttaminen

Tämä vie meidät näiden vinkkien pääaiheeseen. Näyttöohjaimen mukauttaminen on komentosarja, joten luo ensin komentosarja. Nimi on mielivaltainen, mutta tässä tapauksessa OnScreenDpad se on .

Skripti näyttää tältä:

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

Voit luoda näyttöohjauksen OnScreenControl mukautusluokan perimällä sen Mukauta-luokasta. Lisäksi, jos haluat vastaanottaa erilaisia kosketustapahtumia, peri kohdeliittymä. Tässä käsitellään "kosketettaessa", "liikuttaessa koskettaessa", "kun kosketus vapautetaan" ja "ennen vetämistä", joten myös seuraavat rajapinnat kuvataan.

public class OnScreenDpad
  : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Käyttöliittymän sisältö
IPointerDownHandler Kun kosketat
IPointerUpHandler Kun vapautat kosketuksen
IDragHandler Kun liikut koskettaessasi
IInitializePotentialDragHandler Ennen vetämisen aloittamista

Seuraavat kentät ilmoitetaan:

controlPathInternalOnScreenControl vaaditaan, jos perit luokasta. Siinä on merkkijono siitä, mihin syöttölaitteen painikkeeseen kartoitetaan, mutta periaatteessa voit kirjoittaa sen sellaisenaan. InputControl Määritteen tulisi kuitenkin sisältää säilytettävä arvo (tässä tapauksessa Vector2).

_objectPosition_objectSizeHalf ja pidä puolet painikkeen asennosta ja koosta etukäteen ja käytä sitä myöhemmin laskelmiin.

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

Menetelmä, jota kutsutaan Start objektin alustuksen jälkeen, saa puolet kankaalle olevan painikkeen sijainnista ja koosta. Koko ottaa huomioon myös mittakaavan. Start Se käsitellään menetelmällä, mutta jos sitä voidaan lopulta käyttää oikein laskennassa, hankinnan ajoitus voi olla mikä tahansa.

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

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

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

OnInitializePotentialDrag kutsutaan, kun haluat aloittaa vetämisen kosketuksen jälkeen. Vetämisen OnDrag aikana menetelmää kutsutaan. Kynnys on asetettu estämään vetotuomio jossain määrin, jotta sormi ei liiku hieman ja vetotuomio ei tapahdu pelkän kosketuksen vuoksi.

Tällä kertaa, koska se on tulo, joka olettaa, että haluat suorittaa hienosäätötoiminnon, poista tämä kynnysasetus käytöstä ja tee välittömästi vetotuomio. eventData.useDragThreshold false Voit ohittaa kynnyksen määrittämällä arvoksi .

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

Alla on tapahtumat, joita kutsutaan kosketettaessa, vedettäessä ja vapautettaessa. OnPointerDown OnDrag Koska ja , kukin suorittaa Operate saman syötteen käsittelyn, joten luomme erillisen menetelmän ja kutsumme sitä. OnPointerUp Siirrä se nyt menetelmään ilmoittaaksesi SendValueToControl Vector2.zero ohjausobjektille, että se on lopettanut kirjoittamisen.

/// <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 Menetelmä on ydinsuuntaohjaimen syöttötoiminto.

Ensinnäkin kosketusasento voidaan saada , mutta koska tämä koordinaatti on pelinäytön koordinaatti eventData.position , RectTransformUtility.ScreenPointToLocalPointInRectangle menetelmä muuntaa kankaalle koordinaateiksi. Välitettävät arvot ovat "canvas", "touch position", "camera" ja " RectTransformreceiving variable".

Kun olet saanut "kosketusasennon kankaalle", muunna se painikkeen sijaintiin alkuperänä. Vähennä vain objektin_objectPosition sijainti ().

Seuraavaksi, koska kosketussijainti on edelleen numero kankaalla, muunna tämä arvo suhteeksi 0 ~ 1. Jos jaat puoleen painikkeen koosta, kosketusasento painikkeen alueella on 0~1. Jos vedät koskettamalla, arvo on 1 tai enemmän, koska se hyväksyy toiminnot myös painikkeen ulkopuolella. Vector2.ClampMagnitude Tee tämä menetelmällä niin, että se ei ylitä 1.

Lopuksi siirrä menetelmälle 0 ~ 1: ksi muunnettu syöttöarvo SendValueToControl . Näyttöohjaus tekee loput puolestasi.

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

Liitä luomasi komentosarja painikkeeseen. Tätä toimintoa käsitellään peliohjaimen vasemman sauvan toimintana.

Kokeile siirtää peliä ja koskettaa painikkeita. Mielestäni voit nähdä, että saatu arvo muuttuu kosketusasennon mukaan. Voit myös nähdä, että vaikka vedät koskettaessasi, arvo muuttuu vetoasennon mukaan.