Tilpas skærmkontrollen for at implementere D-blokken
Miljø til bekræftelse
- Windows
-
- Windows 11
- Enhedslistens redaktør
-
- 2020.3.25f1
- Input System Pakke
-
- 1.2.0
Forudsætninger for dette tip
Følgende indstillinger er foretaget på forhånd som en forudsætning for beskrivelsen af dette tip.
Du bør også være bekendt med følgende tips:
- Brug handlingskort til at tildele knapper til spiladfærd
- Brug berøringsoptimerede inputkontroller med Kontrol på skærmen
On-Screen Control Stick er standardorienteringsoperationen
On-Screen Stick implementeres som en virtuel stick, der replikerer driften af en pind svarende til den, der findes på en fysisk controller. For eksempel, hvis du vil flytte den til højre, kan du først røre ved skærmen for at røre ved pinden og derefter skubbe den til højre for at slå pinden ned.
Det er let at forestille sig som en pindoperation, men tværtimod, når du straks vil flytte den til højre, (1) berøring, (2) skub til højre, Da det kræver en to-trins operation, vil svaret uundgåeligt blive lidt forsinket. Dette gælder især, når du skal foretage en hurtig retningsændring i træk.
D-blok, der bestemmer retningen i berøringsøjeblikket (ikke-standard)
Den bedste inputmetode til hurtig retningsinput er en, der kan bestemme retningen i berøringsøjeblikket ved at placere noget som en D-blok eller piletast. Det er ikke lavet af Unity, men i mit spil Little Saber placerer jeg piletasterne, så du hurtigt kan bevæge dig i den retning, du rører ved. Selvfølgelig kan du også glide op eller venstre, mens du rører for at skifte bevægelse.
Imidlertid er On-Screen Control-standarden ikke let at placere og implementere, fordi der kun er On-Screen Sticks og On-Screen Buttons.
Du kan også oprette en pseudo-D-pad ved at arrangere fire knapper som vist i figuren nedenfor, men det er ubelejligt, fordi du ikke kan indtaste diagonalt. Hvis du placerer 8 knapper, er diagonal betjening mulig, men flowretningsbetjening som "← ↙ ↓" er stadig ikke mulig.
Opret en retningsbestemt pude med tilpasning af skærmkontrol
Som du kan se, leveres skærmkontrol kun som standard med Stick og Button, men du kan tilpasse de manglende funktioner med dine egne scripts. Så her vil jeg gerne oprette en retningspude med tilpasning af skærmkontrol.
Handlingsoversigt
Vi vil bruge handlingskortet, men vi vil bruge det, der blev oprettet i de foregående tip, som det er, så proceduren udelades.
Du har også skrevet noget kode.
Placering af objekter
Placer et tekstområde for at få vist dit input og en knap, der erstatter D-blokken. I dette tilfælde er knapperne arrangeret, men du kan erstatte dem med et billede, der er lettere at forstå.
Script til visning af input
Da kontrol på skærmen erstatter berøring med fysisk controllerinteraktion, Opret et script, der viser dit input i tekst, mens handlingsoversigten fungerer.
Indholdet er det samme som før, så jeg vil udelade forklaringen.
- Brug handlingskort til at tildele knapper til spiladfærd
- Brug berøringsoptimerede inputkontroller med Kontrol på skærmen
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}";
}
}
Når du har konfigureret det, skal du først kontrollere, om det fungerer med dit tastatur eller gamepad.
Tilpasning af kontrolelementer på skærmen
Dette bringer os til hovedemnet for disse tip.
Tilpasning af kontrolelementet på skærmen er et script, så opret først et script.
Navnet er vilkårligt, men i dette tilfælde OnScreenDpad
er det .
Scriptet ser sådan ud:
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);
}
}
Du opretter en OnScreenControl
tilpasningsklasse for kontrolelementer på skærmen ved at arve fra klassen Tilpas.
For at modtage forskellige berøringshændelser skal du desuden arve målgrænsefladen.
Her behandles "når du rører", "når du bevæger dig under berøring", "når berøringen frigives" og "før du trækker", så følgende grænseflader beskrives også henholdsvis.
public class OnScreenDpad
: OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Interface | indhold |
---|---|
IPointerDownHandler | Ved berøring |
IPointerUpHandler | Når du slipper berøringen |
IDragHandler | Når du bevæger dig, mens du rører |
IInitializePotentialDragHandler | Før du begynder at trække |
Følgende felter erklæres:
controlPathInternal
OnScreenControl
er påkrævet, hvis du arver fra en klasse.
Den indeholder en streng af hvilken knap på inputenheden, der skal kortlægges til, men dybest set kan du skrive den som den er.
InputControl
Attributten skal dog indeholde den værdi, der skal bevares (Vector2 i dette tilfælde).
_objectPosition
_objectSizeHalf
og hold halvdelen af knappens position og størrelse på forhånd og brug den senere til beregninger.
[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;
Metoden, der kaldes Start
efter objektet er initialiseret, får halvdelen af positionen og størrelsen af knappen på lærredet.
Størrelsen tager også højde for skalaen.
Start
Det behandles ved hjælp af en metode, men hvis det kan bruges korrekt i beregningen i sidste ende, kan erhvervelsestidspunktet være hvor som helst.
// <summary>
// オブジェクトが動作する最初のタイミングで1回だけ呼ばれます。
// </summary>
private void Start()
{
var rectTransform = (RectTransform)base.transform;
// オブジェクトの位置を取得
_objectPosition = rectTransform.anchoredPosition;
// オブジェクトのサイズの半分を取得 (スケールサイズも考慮)
_objectSizeHalf = rectTransform.sizeDelta * rectTransform.localScale / 2f;
}
OnInitializePotentialDrag
kaldes, når du vil begynde at trække efter berøring.
Mens du trækker, OnDrag
kaldes metoden.
En tærskel er indstillet til at forhindre trækdom til en vis grad, så fingeren ikke bevæger sig lidt, og trækdommen ikke opstår på grund af operationen med blot at røre.
Denne gang, da det er et input, der antager, at du vil udføre en finjusteringsoperation, skal du deaktivere denne tærskelindstilling og straks foretage en trækdom.
eventData.useDragThreshold
false
Du kan tilsidesætte tærsklen ved at indstille til .
<summary>ドラッグの初期化処理として呼ばれます。</summary>
<param name="eventData">タッチ情報。</param>
public void OnInitializePotentialDrag(PointerEventData eventData)
{
// タッチのスライド操作を即座に発生させたいのでドラッグ開始までの閾値を無効にします
eventData.useDragThreshold = false;
}
Nedenfor er de begivenheder, der kaldes, når du henholdsvis rører, trækker og slipper.
OnPointerDown
OnDrag
Siden og , hver udfører Operate
den samme inputbehandling, så vi opretter en separat metode og kalder den.
OnPointerUp
Send det nu til metoden for at underrette kontrollen om, at den er stoppet med at SendValueToControl
Vector2.zero
skrive.
<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
Metoden er den centrale D-pad-indgangsoperation.
Først og fremmest berøringspositionen kan opnås med , men da denne koordinat er koordinaten på eventData.position
spilskærmen,
RectTransformUtility.ScreenPointToLocalPointInRectangle
metode til at konvertere til lærredskoordinater.
De værdier, der skal overføres, er "lærred", "berøringsposition", "kamera" og " RectTransform
modtagevariabel".
Når du har fået "berøringspositionen på lærredet", skal du konvertere den til knappens position som oprindelse.
Bare træk objektets_objectPosition
position () fra.
Dernæst, da berøringspositionen stadig er et tal på lærredet, skal du konvertere denne værdi til et forhold på 0 ~ 1.
Hvis du dividerer med halvdelen af knappens størrelse, vil berøringspositionen inden for knappens rækkevidde være 0 ~ 1.
Hvis du trækker med berøring, vil værdien være 1 eller mere, fordi den accepterer handlinger selv uden for knappen.
Vector2.ClampMagnitude
Gør dette i metoden, så den ikke overstiger 1.
Til sidst skal du sende inputværdien SendValueToControl
konverteret til 0 ~ 1 til metoden.
Skærmkontrollen gør resten for dig.
<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);
}
Vedhæft det script, du oprettede, til knappen. Denne handling er indstillet til at blive behandlet som betjeningen af den venstre pind på gamepad.
Prøv at flytte spillet, og tryk på knapperne. Jeg tror, du kan se, at den opnåede værdi ændres afhængigt af berøringspositionen. Du kan også se, at selvom du trækker, mens du rører, ændres værdien afhængigt af trækpositionen.