Pielāgojiet ekrānā redzamo vadīklu, lai ieviestu D-pad

Lapa atjaunota :
Lapas izveides datums :

Verifikācijas vide

Windows
  • Operētājsistēmā Windows 11
Vienotības redaktors
  • 2020.3.25f1
Ievades sistēmas pakete
  • 1.2.0

Priekšnoteikumi šim padomam

Tālāk norādītie iestatījumi ir veikti iepriekš kā priekšnoteikums šī padoma aprakstam.

Jums jāzina arī šādi padomi:

Ekrāna vadības nūja ir standarta orientācijas darbība

Ekrāna nūja tiek īstenota kā virtuāla nūja, atkārtojot nūjas darbību, kas ir līdzīga tai, kas atrodama fiziskajā kontrolierī. Piemēram, ja vēlaties to pārvietot pa labi, vispirms varat pieskarties ekrānam, lai pieskartos nūjai, un pēc tam pabīdīt to pa labi, lai notriektu nūju.

To ir viegli iedomāties kā nūjas darbību, bet gluži pretēji, kad vēlaties to nekavējoties pārvietot pa labi, (1) pieskarties, (2) slīdēt pa labi, Tā kā tam nepieciešama divpakāpju darbība, reakcija neizbēgami būs nedaudz aizkavēta. Tas jo īpaši attiecas uz gadījumiem, kad jums ir nepieciešams ātri mainīt virzienu pēc kārtas.

D-pad, kas nosaka virzienu pieskāriena brīdī (nestandarta)

Labākā ievades metode ātrai virziena ievadei ir tāda, kas var noteikt virzienu pieskaršanās brīdī, ievietojot kaut ko līdzīgu D-pad vai bultas taustiņam. To nav veidojusi Unity, bet savā spēlē Little Saber es novietoju bulttaustiņus, lai jūs varētu ātri pārvietoties virzienā, kuram pieskaraties. Protams, jūs varat arī slīdēt uz augšu vai pa kreisi, pieskaroties, lai pārslēgtu kustības.

Tomēr ekrāna vadības standartu nav viegli ievietot un ieviest, jo ir tikai ekrāna nūjas un ekrāna pogas.

Varat arī izveidot pseido-D-spilventiņu, sakārtojot četras pogas, kā parādīts zemāk redzamajā attēlā, taču tas ir neērti, jo jūs nevarat ievadīt pa diagonāli. Ja ievietojat 8 pogas, diagonālā darbība ir iespējama, bet plūsmas virziena darbība, piemēram, "← ↙ ↓", joprojām nav iespējama.

Virziena paliktņa izveide ar ekrāna vadības pielāgošanu

Kā redzat, ekrāna vadība ir standarta komplektācijā tikai ar nūju un pogu, taču trūkstošās funkcijas varat pielāgot ar saviem skriptiem. Tāpēc šeit es vēlētos izveidot virziena spilventiņu ar ekrāna vadības pielāgošanu.

Rīcības karte

Mēs izmantosim rīcības karti, bet mēs izmantosim iepriekšējos padomos izveidoto, kā tas ir, tāpēc procedūra tiek izlaista.

Tu esi uzrakstījis arī kādu kodu.

Objektu pozicionēšana

Novietojiet teksta apgabalu, lai parādītu ievadi, un pogu, kas aizstāj D-pad. Šajā gadījumā pogas ir sakārtotas, bet jūs varat tās aizstāt ar vieglāk saprotamu attēlu.

Skripts, lai parādītu ievadi

Tā kā ekrāna vadība aizstāj pieskārienu ar fiziskā kontrollera mijiedarbību, Izveidojiet skriptu, kas parāda jūsu ievadi tekstā, kad darbojas darbību karte.

Saturs ir tāds pats kā iepriekš, tāpēc es izlaidīšu skaidrojumu.

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ēc iestatīšanas vispirms pārbaudiet, vai tas darbojas ar tastatūru vai spēļu paneli.

Ekrānā redzamo vadīklu pielāgošana

Tas mūs noved pie šo padomu galvenās tēmas. Ekrāna vadīklas pielāgošana ir skripts, tāpēc vispirms izveidojiet skriptu. Nosaukums ir patvaļīgs, bet šajā gadījumā OnScreenDpad tas ir .

Skripts izskatās šādi:

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

Pielāgošanas klasi Ekrāna vadīkla var izveidot, OnScreenControl pārmantojot to no klases Pielāgot. Turklāt, lai saņemtu dažādus pieskārienu notikumus, mantojiet mērķa saskarni. Šeit tiek apstrādāti "pieskaroties", "pārvietojoties, pieskaroties", "kad pieskāriens tiek atbrīvots" un "pirms vilkšanas", tāpēc attiecīgi tiek aprakstītas arī šādas saskarnes.

public class OnScreenDpad
  : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Interfeisa saturs
IPointerDownHandler Pieskaroties
IPointerUpHandler Atlaižot skārienvadību
IDragHandler Kad jūs pārvietojaties, pieskaroties
IInitializePotentialDragHandler Pirms sākat vilkt

Deklarē šādus laukus:

controlPathInternalOnScreenControl ir nepieciešams, ja mantojat no klases. Tajā ir virkne, uz kuru ievades ierīces pogu kartēt, bet būtībā jūs varat to rakstīt tādu, kāda tā ir. InputControl Tomēr atribūtā jābūt saglabājamai vērtībai (šajā gadījumā Vector2).

_objectPosition_objectSizeHalf un iepriekš turiet pusi no pogas pozīcijas un izmēra un izmantojiet to vēlāk aprēķiniem.

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

Metode, ko sauc pēc Start objekta inicializēšanas, iegūst pusi no pogas pozīcijas un izmēra uz audekla. Lielumā tiek ņemta vērā arī skala. Start To apstrādā ar metodi, bet, ja to galu galā var pareizi izmantot aprēķinā, iegādes laiks var būt jebkur.

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

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

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

OnInitializePotentialDrag tiek izsaukts, kad vēlaties sākt vilkt pēc pieskāriena. Velkot, OnDrag metode tiek saukta. Ir iestatīts slieksnis, lai novērstu vilkšanas spriedumu zināmā mērā, lai pirksts nedaudz nekustētos un vilkšanas spriedums nenotiktu vienkārši pieskaršanās darbības dēļ.

Šoreiz, tā kā tā ir ievade, kas pieņem, ka vēlaties veikt precizējošu darbību, atspējojiet šo sliekšņa iestatījumu un nekavējoties veiciet vilkšanas spriedumu. eventData.useDragThreshold false Varat ignorēt slieksni, iestatot uz .

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

Zemāk ir notikumi, kas tiek izsaukti, attiecīgi pieskaroties, velkot un atlaižot. OnPointerDown OnDrag Tā kā un , katrs veic Operate vienu un to pašu ievades apstrādi, tāpēc mēs izveidojam atsevišķu metodi un saucam to. OnPointerUp Tagad nododiet to metodei, lai SendValueToControl Vector2.zero paziņotu vadīklai, ka tā ir pārtraukusi rakstīt.

/// <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 Metode ir galvenā D-pad ievades darbība.

Pirmkārt, pieskāriena pozīciju var iegūt ar , bet tā kā šī koordināta ir spēles ekrāna koordināta eventData.position , RectTransformUtility.ScreenPointToLocalPointInRectangle metode, lai pārvērstu par audekla koordinātām. Nododamās vērtības ir "audekls", "pieskāriena pozīcija", "kamera" un "uztverošais mainīgais" RectTransform.

Pēc tam, kad esat ieguvis "pieskāriena pozīciju uz audekla", pārveidojiet to par pogas pozīciju kā sākumu. Vienkārši atņemiet objekta pozīciju ()._objectPosition

Pēc tam, tā kā pieskāriena pozīcija joprojām ir skaitlis uz audekla, konvertējiet šo vērtību uz attiecību 0 ~ 1. Ja jūs dalāt ar pusi no pogas izmēra, pieskāriena pozīcija pogas diapazonā būs 0 ~ 1. Ja velkat ar pieskārienu, vērtība būs 1 vai lielāka, jo tā pieņem darbības pat ārpus pogas. Vector2.ClampMagnitude Dariet to metodē tā, lai tas nepārsniegtu 1.

Visbeidzot, nododiet metodei ievades vērtību SendValueToControl , kas konvertēta uz 0 ~ 1. Ekrāna vadība pārējo dara jūsu vietā.

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

Pievienojiet pogai izveidoto skriptu. Šī darbība ir iestatīta kā Gamepad kreisās nūjas darbība.

Mēģiniet pārvietot spēli un pieskarieties pogām. Es domāju, ka jūs varat redzēt, ka iegūtā vērtība mainās atkarībā no pieskāriena pozīcijas. Turklāt jūs varat redzēt, ka pat tad, ja velkat, pieskaroties, vērtība mainās atkarībā no vilkšanas pozīcijas.