Prilagajanje nadzora na zaslonu za izvedbo tipkovnice D-pad
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:
- Uporaba zemljevidov dejanj za dodeljevanje gumbov vedenju v igri
- Uporaba vhodnih kontrolnikov, optimiziranih za dotik, z upravljanjem na zaslonu
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.
- Uporaba zemljevidov dejanj za dodeljevanje gumbov vedenju v igri
- Uporaba vhodnih kontrolnikov, optimiziranih za dotik, z upravljanjem na zaslonu
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:
controlPathInternal
OnScreenControl
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 " RectTransform
sprejemna 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.