Personalizați controlul de pe ecran pentru a implementa D-pad-ul
Mediul de verificare
- Windows
-
- Ferestre 11
- Unity Editor
-
- 2020.3.25F1
- Pachet sistem de intrare
-
- 1.2.0
Cerințe preliminare pentru acest sfat
Următoarele setări au fost făcute în avans ca premisă pentru descrierea acestui sfat.
De asemenea, trebuie să cunoașteți următoarele sfaturi:
- Utilizați hărți de acțiune pentru a atribui butoane comportamentelor de joc
- Utilizarea comenzilor de intrare optimizate pentru atingere cu Control pe ecran
Control Stick-ul de pe ecran este operația standard de orientare
On-Screen Stick este implementat ca un stick virtual, replicând funcționarea unui stick similar cu cel găsit pe un controler fizic. De exemplu, dacă doriți să îl mutați spre dreapta, puteți atinge mai întâi ecranul pentru a atinge stickul, apoi glisați-l spre dreapta pentru a bate stick-ul în jos.
Este ușor de imaginat ca o operație de băț, dar dimpotrivă, atunci când doriți să o mutați imediat spre dreapta, (1) atingeți, (2) glisați spre dreapta, Deoarece necesită o operație în două etape, răspunsul va fi în mod inevitabil puțin întârziat. Acest lucru este valabil mai ales atunci când trebuie să faceți o schimbare rapidă de direcție la rând.
D-pad care determină direcția în momentul atingerii (non-standard)
Cea mai bună metodă de introducere pentru introducerea rapidă a direcției este una care poate determina direcția în momentul atingerii prin plasarea a ceva de genul unui D-pad sau a unei taste săgeată. Nu este făcut de Unity, dar în jocul meu Little Saber, plasez tastele săgeată astfel încât să vă puteți deplasa rapid în direcția pe care o atingeți. Desigur, puteți, de asemenea, să glisați în sus sau spre stânga în timp ce atingeți pentru a comuta mișcările.
Cu toate acestea, standardul de control pe ecran nu este ușor de plasat și implementat, deoarece există doar stick-uri pe ecran și butoane pe ecran.
De asemenea, puteți crea un pseudo-D-pad aranjând patru butoane așa cum se arată în figura de mai jos, dar este incomod deoarece nu puteți introduce în diagonală. Dacă plasați 8 butoane, este posibilă funcționarea diagonală, dar funcționarea direcției de curgere, cum ar fi "← ↙ ↓", nu este încă posibilă.
Crearea unui pad direcțional cu personalizarea Control pe ecran
După cum puteți vedea, controlul pe ecran vine standard numai cu Stick și Button, dar puteți personaliza caracteristicile lipsă cu propriile scripturi. Deci, aici aș dori să creez un pad direcțional cu personalizarea controlului pe ecran.
Harta de acțiune
Vom folosi harta acțiunii, dar o vom folosi pe cea creată în sfaturile anterioare așa cum este, astfel încât procedura este omisă.
Ai scris și un cod.
Poziționarea obiectelor
Plasați o zonă de text pentru a afișa intrarea și un buton care înlocuiește D-pad-ul. În acest caz, butoanele sunt aranjate, dar le puteți înlocui cu o imagine mai ușor de înțeles.
Script pentru afișarea intrărilor
Deoarece Controlul vizual înlocuiește atingerea cu interacțiunea fizică a controlerului, Creați un script care afișează intrarea în text pe măsură ce funcționează harta de acțiune.
Conținutul este același ca înainte, așa că voi omite explicația.
- Utilizați hărți de acțiune pentru a atribui butoane comportamentelor de joc
- Utilizarea comenzilor de intrare optimizate pentru atingere cu Control pe ecran
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}";
}
}
După configurare, verificați mai întâi dacă funcționează cu tastatura sau gamepadul.
Personalizarea comenzilor de pe ecran
Acest lucru ne aduce la subiectul principal al acestor sfaturi.
Personalizarea controlului pe ecran este un script, deci mai întâi creați un script.
Numele este arbitrar, dar în acest caz OnScreenDpad
este .
Scenariul arată astfel:
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);
}
}
Creați o OnScreenControl
clasă de particularizare Control vizual moștenind de la clasa Particularizare.
În plus, pentru a primi diverse evenimente tactile, moșteniți interfața țintă.
Aici, sunt procesate "când atingeți", "când vă deplasați în timp ce atingeți", "când atingeți eliberarea" și "înainte de tragere", astfel încât sunt descrise și următoarele interfețe.
public class OnScreenDpad
: OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Conținutul interfeței | |
---|---|
IPointerDownHandler | Când este atins |
IPointerUpHandler | Când eliberați atingerea |
IDragHandler | Când vă mișcați în timp ce atingeți |
IInitializePotentialDragHandler | Înainte de a începe să trageți |
Se declară următoarele câmpuri:
controlPathInternal
OnScreenControl
este necesar dacă moșteniți de la o clasă.
Acesta deține un șir de buton al dispozitivului de intrare la care să mapați, dar practic îl puteți scrie așa cum este.
InputControl
Cu toate acestea, atributul trebuie să conțină valoarea care trebuie păstrată (Vector2 în acest caz).
_objectPosition
_objectSizeHalf
și țineți apăsată jumătate din poziția și dimensiunea butonului în avans și utilizați-l mai târziu pentru calcule.
[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, numită Start
după inițializarea obiectului, obține jumătate din poziția și dimensiunea butonului de pe pânză.
Dimensiunea ia în considerare și scara.
Start
Este procesat printr-o metodă, dar dacă poate fi utilizat corect în calcul în cele din urmă, momentul achiziției poate fi oriunde.
// <summary>
// オブジェクトが動作する最初のタイミングで1回だけ呼ばれます。
// </summary>
private void Start()
{
var rectTransform = (RectTransform)base.transform;
// オブジェクトの位置を取得
_objectPosition = rectTransform.anchoredPosition;
// オブジェクトのサイズの半分を取得 (スケールサイズも考慮)
_objectSizeHalf = rectTransform.sizeDelta * rectTransform.localScale / 2f;
}
OnInitializePotentialDrag
este apelat atunci când doriți să începeți să trageți după atingere.
În timp ce trageți, OnDrag
se numește metoda.
Un prag este setat pentru a preveni judecata de tragere într-o oarecare măsură, astfel încât degetul să nu se miște puțin și judecata de tragere să nu apară din cauza operației de simplă atingere.
De data aceasta, deoarece este o intrare care presupune că doriți să efectuați o operație de reglare fină, dezactivați această setare de prag și faceți imediat o judecată de tragere.
eventData.useDragThreshold
false
Puteți suprascrie pragul setând la .
<summary>ドラッグの初期化処理として呼ばれます。</summary>
<param name="eventData">タッチ情報。</param>
public void OnInitializePotentialDrag(PointerEventData eventData)
{
// タッチのスライド操作を即座に発生させたいのでドラッグ開始までの閾値を無効にします
eventData.useDragThreshold = false;
}
Mai jos sunt evenimentele apelate la atingere, tragere și, respectiv, eliberare.
OnPointerDown
OnDrag
Deoarece și , fiecare efectuează Operate
aceeași procesare de intrare, așa că creăm o metodă separată și o numim.
OnPointerUp
Acum, treceți-l la metodă pentru a SendValueToControl
Vector2.zero
notifica controlul că a încetat să tasteze.
<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 este operația de intrare D-pad de bază.
În primul rând, poziția tactilă poate fi obținută cu , dar din moment ce această coordonată este coordonata ecranului de eventData.position
joc,
RectTransformUtility.ScreenPointToLocalPointInRectangle
Metoda de conversie în coordonate de pânză.
Valorile care trebuie transmise sunt "canvas", "touch position", "camera" și " RectTransform
receiving variable".
După obținerea "poziției tactile pe pânză", convertiți-o în poziția butonului ca origine.
Doar scădeți poziția () obiectului_objectPosition
.
Apoi, deoarece poziția tactilă este încă un număr pe pânză, convertiți această valoare într-un raport de 0 ~ 1.
Dacă împărțiți la jumătate dimensiunea butonului, poziția tactilă în intervalul butonului va fi 0 ~ 1.
Dacă trageți prin atingere, valoarea va fi 1 sau mai mult, deoarece acceptă operații chiar și în afara butonului.
Vector2.ClampMagnitude
Faceți acest lucru în metodă, astfel încât să nu depășească 1.
În cele din urmă, treceți valoarea SendValueToControl
de intrare convertită la 0 ~ 1 la metodă.
Controlul de pe ecran face restul pentru dvs.
<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);
}
Atașați scriptul pe care l-ați creat la buton. Această acțiune este setată să fie tratată ca funcționarea stick-ului stâng al gamepadului.
Încercați să mutați jocul și atingeți butoanele. Cred că puteți vedea că valoarea obținută se modifică în funcție de poziția tactilă. De asemenea, puteți vedea că, chiar dacă trageți în timp ce atingeți, valoarea se modifică în funcție de poziția de tragere.