Pas de besturing op het scherm aan om de D-pad te implementeren
Verificatieomgeving
- Ramen
-
- Voor Windows 11
- Unity Editor
-
- 2020.3.25f1
- Input systeem pakket
-
- 1.2.0
Vereisten voor deze tip
De volgende instellingen zijn vooraf gemaakt als uitgangspunt voor de beschrijving van deze tip.
U moet ook bekend zijn met de volgende tips:
- Actiekaarten gebruiken om knoppen toe te wijzen aan gamegedrag
- Gebruik voor aanraking geoptimaliseerde invoerbesturingselementen met On-Screen Control
On-Screen Control Stick is de standaard oriëntatiebediening
De On-Screen Stick is geïmplementeerd als een virtuele stick, die de werking van een stick repliceert die vergelijkbaar is met die op een fysieke controller. Als u het bijvoorbeeld naar rechts wilt verplaatsen, kunt u eerst het scherm aanraken om de stick aan te raken en vervolgens naar rechts schuiven om de stick naar beneden te slaan.
Het is gemakkelijk voor te stellen als een stokbediening, maar integendeel, wanneer u het onmiddellijk naar rechts wilt verplaatsen, (1) aanraken, (2) naar rechts schuiven, Omdat het een bewerking in twee stappen vereist, zal de reactie onvermijdelijk een beetje vertraagd zijn. Dit geldt vooral wanneer u snel achter elkaar van richting moet veranderen.
D-pad die de richting bepaalt op het moment van aanraking (niet-standaard)
De beste invoermethode voor snelle richtingsinvoer is er een die de richting op het moment van aanraken kan bepalen door iets als een D-pad of pijltoets te plaatsen. Het is niet gemaakt door Unity, maar in mijn spel Little Saber plaats ik de pijltjestoetsen zo dat je snel kunt bewegen in de richting die je aanraakt. Natuurlijk kun je ook omhoog of naar links schuiven tijdens het aanraken om van beweging te wisselen.
De On-Screen Control-standaard is echter niet eenvoudig te plaatsen en te implementeren omdat er alleen On-Screen Sticks en On-Screen Buttons zijn.
U kunt ook een pseudo-D-pad maken door vier knoppen te rangschikken zoals weergegeven in de onderstaande afbeelding, maar het is onhandig omdat u niet diagonaal kunt invoeren. Als u 8 knoppen plaatst, is diagonale bediening mogelijk, maar stroomrichtingsbediening zoals "← ↙ ↓" is nog steeds niet mogelijk.
Een richtingspad maken met aanpassing van Besturingselement op het scherm
Zoals u kunt zien, wordt On-Screen Control alleen standaard geleverd met Stick en Button, maar u kunt de ontbrekende functies aanpassen met uw eigen scripts. Dus hier wil ik een directioneel pad maken met aanpassing van On-Screen Control.
Actiekaart
We zullen de actiekaart gebruiken, maar we zullen degene gebruiken die in de vorige tips is gemaakt zoals deze is, dus de procedure wordt weggelaten.
Je hebt ook wat code geschreven.
Objecten positioneren
Plaats een tekstgebied om uw invoer weer te geven en een knop die de D-pad vervangt. In dit geval zijn de knoppen gerangschikt, maar u kunt ze vervangen door een afbeelding die gemakkelijker te begrijpen is.
Script om invoer weer te geven
Omdat On-Screen Control touch vervangt door fysieke controllerinteractie, Maak een script dat uw invoer in tekst weergeeft terwijl de actiekaart werkt.
De inhoud is hetzelfde als voorheen, dus ik zal de uitleg weglaten.
- Actiekaarten gebruiken om knoppen toe te wijzen aan gamegedrag
- Gebruik voor aanraking geoptimaliseerde invoerbesturingselementen met On-Screen Control
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}";
}
}
Controleer na het instellen eerst of het werkt met uw toetsenbord of gamepad.
Besturingselementen op het scherm aanpassen
Dit brengt ons bij het hoofdonderwerp van deze tips.
Het aanpassen van het besturingselement op het scherm is een script, dus maak eerst een script.
De naam is arbitrair, maar in dit geval OnScreenDpad
is het .
Het script ziet er als volgt uit:
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);
}
}
U maakt een OnScreenControl
aanpassingsklasse Besturingselement op het scherm door over te nemen van de klasse Aanpassen.
Als u bovendien verschillende aanraakgebeurtenissen wilt ontvangen, neemt u de doelinterface over.
Hier worden "bij aanraken", "bij bewegen tijdens het aanraken", "wanneer de aanraking wordt losgelaten" en "voor het slepen" verwerkt, zodat respectievelijk ook de volgende interfaces worden beschreven.
public class OnScreenDpad
: OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Inhoud van de interface | |
---|---|
IPointerDownHandler | Bij aanraking |
IPointerUpHandler | Wanneer u de aanraking loslaat |
IDragHandler | Wanneer u beweegt tijdens het aanraken |
IInitializePotentialDragHandler | Voordat u begint met slepen |
De volgende velden worden gedeclareerd:
controlPathInternal
OnScreenControl
is vereist als u erft van een klasse.
Het bevat een reeks van welke knop van het invoerapparaat moet worden toegewezen, maar in principe kunt u het schrijven zoals het is.
InputControl
Het attribuut moet echter de te behouden waarde bevatten (vector2 in dit geval).
_objectPosition
_objectSizeHalf
en houd van tevoren de helft van de positie en grootte van de knop vast en gebruik deze later voor berekeningen.
[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;
De methode, die wordt aangeroepen Start
nadat het object is geïnitialiseerd, krijgt de helft van de positie en grootte van de knop op het canvas.
De grootte houdt ook rekening met de schaal.
Start
Het wordt verwerkt door een methode, maar als het uiteindelijk correct kan worden gebruikt in de berekening, kan de acquisitietiming overal zijn.
// <summary>
// オブジェクトが動作する最初のタイミングで1回だけ呼ばれます。
// </summary>
private void Start()
{
var rectTransform = (RectTransform)base.transform;
// オブジェクトの位置を取得
_objectPosition = rectTransform.anchoredPosition;
// オブジェクトのサイズの半分を取得 (スケールサイズも考慮)
_objectSizeHalf = rectTransform.sizeDelta * rectTransform.localScale / 2f;
}
OnInitializePotentialDrag
wordt aangeroepen wanneer u wilt beginnen met slepen na aanraking.
Tijdens het slepen OnDrag
wordt de methode aangeroepen.
Er is een drempel ingesteld om het slepen tot op zekere hoogte te voorkomen, zodat de vinger niet een beetje beweegt en het sleepoordeel niet optreedt als gevolg van de werking van gewoon aanraken.
Deze keer, omdat het een invoer is die ervan uitgaat dat u een fijnafstemmingsbewerking wilt uitvoeren, schakelt u deze drempelinstelling uit en maakt u onmiddellijk een sleepoordeel.
eventData.useDragThreshold
false
U kunt de drempel overschrijven door in te stellen op .
<summary>ドラッグの初期化処理として呼ばれます。</summary>
<param name="eventData">タッチ情報。</param>
public void OnInitializePotentialDrag(PointerEventData eventData)
{
// タッチのスライド操作を即座に発生させたいのでドラッグ開始までの閾値を無効にします
eventData.useDragThreshold = false;
}
Hieronder staan de gebeurtenissen die worden genoemd bij respectievelijk aanraken, slepen en loslaten.
OnPointerDown
OnDrag
Aangezien en , voert elk dezelfde invoerverwerking uit Operate
, dus we maken een afzonderlijke methode en noemen deze aan.
OnPointerUp
Geef het nu door aan de methode om het besturingselement te SendValueToControl
Vector2.zero
laten weten dat het is gestopt met typen.
<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
De methode is de kern D-pad input operatie.
Allereerst kan de aanraakpositie worden verkregen met , maar aangezien deze coördinaat de coördinaat van het eventData.position
spelscherm is,
RectTransformUtility.ScreenPointToLocalPointInRectangle
methode om te converteren naar canvascoördinaten.
De door te geven waarden zijn "canvas", "touch position", "camera" en "receiving variable" RectTransform
.
Nadat u de "aanraakpositie op het canvas" hebt gekregen, converteert u deze naar de positie van de knop als de oorsprong.
Trek gewoon de positie () van het_objectPosition
object af.
Aangezien de aanraakpositie nog steeds een getal op het canvas is, converteert u deze waarde vervolgens naar een verhouding van 0 ~ 1.
Als u deelt door de helft van de grootte van de knop, is de aanraakpositie binnen het bereik van de knop 0 ~ 1.
Als u sleept met aanraken, is de waarde 1 of meer omdat deze bewerkingen accepteert, zelfs buiten de knop.
Vector2.ClampMagnitude
Doe dit in de methode zodat deze niet hoger is dan 1.
Geef ten slotte de invoerwaarde SendValueToControl
geconverteerd naar 0 ~ 1 door aan de methode.
De On-Screen Control doet de rest voor je.
<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);
}
Voeg het script dat u hebt gemaakt toe aan de knop. Deze actie wordt behandeld als de bediening van de linkerstick van de Gamepad.
Probeer het spel te verplaatsen en raak de knoppen aan. Ik denk dat je kunt zien dat de verkregen waarde verandert afhankelijk van de aanraakpositie. U kunt ook zien dat zelfs als u sleept tijdens het aanraken, de waarde verandert afhankelijk van de sleeppositie.