Přizpůsobte si ovládací prvek na obrazovce a implementujte směrový ovladač
Ověřovací prostředí
- Windows
-
- Systém Windows 11
- Editor jednoty
-
- 2020.3.25f1
- Vstupní systémový balíček
-
- 1.2.0
Předpoklady pro tento tip
Následující nastavení byla provedena předem jako předpoklad pro popis tohoto tipu.
Měli byste se také seznámit s následujícími tipy:
- Použití map akcí k přiřazení tlačítek k chování hry
- Použití ovládacích prvků pro zadávání optimalizovaných pro dotykové ovládání s ovládáním na obrazovce
Ovládací páčka na obrazovce je standardní operace orientace
Karta na obrazovce je implementována jako virtuální páčka, která replikuje činnost páčky podobnou té, která se nachází na fyzickém ovladači. Chcete-li ji například posunout doprava, můžete se nejprve dotknout obrazovky a poté ji posunout doprava, abyste ji srazili dolů.
Je snadné si to představit jako operaci páčky, ale naopak, když ji chcete okamžitě posunout doprava, (1) dotkněte se, (2) posuňte doprava, Vzhledem k tomu, že vyžaduje dvoustupňovou operaci, reakce bude nevyhnutelně trochu zpožděna. To platí zejména tehdy, když potřebujete provést rychlou změnu směru v řadě.
směrový ovladač, který určuje směr v okamžiku dotyku (nestandardní)
Nejlepší vstupní metoda pro rychlé zadávání směru je taková, která dokáže určit směr v okamžiku dotyku umístěním něčeho jako směrový ovladač nebo šipka. Není to vyrobeno Unity, ale v mé hře Little Saber jsem umístil klávesy se šipkami tak, abyste se mohli rychle pohybovat ve směru, kterého se dotknete. Samozřejmě můžete také posunout nahoru nebo doleva při dotyku a přepínat pohyby.
Standard ovládání na obrazovce však není snadné umístit a implementovat, protože existují pouze páčky na obrazovce a tlačítka na obrazovce.
Můžete také vytvořit pseudo-D-pad uspořádáním čtyř tlačítek, jak je znázorněno na obrázku níže, ale je to nepohodlné, protože nemůžete zadávat diagonálně. Pokud umístíte 8 tlačítek, je možná diagonální operace, ale operace směru toku, jako je "← ↙ ↓", stále není možná.
Vytvoření směrového panelu s přizpůsobením ovládání na obrazovce
Jak můžete vidět, ovládání na obrazovce je standardně dodáváno pouze s hůlkou a tlačítkem, ale chybějící funkce můžete přizpůsobit pomocí vlastních skriptů. Takže tady bych chtěl vytvořit směrovou podložku s přizpůsobením ovládání na obrazovce.
Mapa akcí
Použijeme akční mapu, ale použijeme tu, která byla vytvořena v předchozích tipech, jak je, takže postup je vynechán.
Také jste napsal nějaký kód.
Umístění objektů
Umístěte textovou oblast pro zobrazení vašeho vstupu a tlačítka, které nahrazuje směrový ovladač. V tomto případě jsou tlačítka uspořádána, ale můžete je nahradit obrázkem, který je srozumitelnější.
Skript pro zobrazení vstupu
Vzhledem k tomu, že ovládání na obrazovce nahrazuje dotykové ovládání fyzickou interakcí ovladače, Vytvořte skript, který zobrazuje váš vstup v textu při fungování mapy akcí.
Obsah je stejný jako předtím, takže vysvětlení vynechám.
- Použití map akcí k přiřazení tlačítek k chování hry
- Použití ovládacích prvků pro zadávání optimalizovaných pro dotykové ovládání s ovládáním na obrazovce
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}";
}
}
Po nastavení nejprve zkontrolujte, zda funguje s klávesnicí nebo gamepadem.
Přizpůsobení ovládacích prvků na obrazovce
To nás přivádí k hlavnímu tématu těchto tipů.
Přizpůsobení ovládacího prvku na obrazovce je skript, takže nejprve vytvořte skript.
Název je libovolný, ale v tomto případě OnScreenDpad
je .
Skript vypadá takto:
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);
}
}
Třídu OnScreenControl
přizpůsobení ovládacího prvku na obrazovce vytvoříte zděděním ze třídy Přizpůsobit.
Kromě toho, pro příjem různých dotykových událostí, zdědit cílové rozhraní.
Zde jsou zpracovány "při dotyku", "při pohybu při dotyku", "při uvolnění dotyku" a "před přetažením", takže jsou také popsána následující rozhraní.
public class OnScreenDpad
: OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Obsah rozhraní | |
---|---|
IPointerDownHandler | Při dotyku |
IPointerUpHandler | Když uvolníte dotyk |
IDragHandler | Když se při dotyku pohybujete |
IInitializePotentialDragHandler | Než začnete přetahovat |
Jsou deklarována následující pole:
controlPathInternal
OnScreenControl
je povinný, pokud dědíte ze třídy.
Obsahuje řetězec, na které tlačítko vstupního zařízení se má mapovat, ale v podstatě jej můžete zapsat tak, jak je.
InputControl
Atribut by však měl obsahovat hodnotu, která má být zachována (v tomto případě Vector2).
_objectPosition
_objectSizeHalf
a předem podržte polovinu pozice a velikosti tlačítka a použijte jej později pro výpočty.
[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, volaná Start
po inicializaci objektu, získá polovinu polohy a velikosti tlačítka na plátně.
Velikost také zohledňuje měřítko.
Start
Zpracovává se metodou, ale pokud ji lze ve výpočtu nakonec správně použít, může být načasování akvizice kdekoliv.
// <summary>
// オブジェクトが動作する最初のタイミングで1回だけ呼ばれます。
// </summary>
private void Start()
{
var rectTransform = (RectTransform)base.transform;
// オブジェクトの位置を取得
_objectPosition = rectTransform.anchoredPosition;
// オブジェクトのサイズの半分を取得 (スケールサイズも考慮)
_objectSizeHalf = rectTransform.sizeDelta * rectTransform.localScale / 2f;
}
OnInitializePotentialDrag
se volá, když chcete začít přetahovat po dotyku.
Při přetahování OnDrag
je metoda volána.
Prahová hodnota je nastavena tak, aby do určité míry zabránila úsudku o odporu, takže prst se trochu nepohybuje a úsudek o tažení nedochází v důsledku operace prostého dotyku.
Tentokrát, protože se jedná o vstup, který předpokládá, že chcete provést operaci jemného doladění, deaktivujte toto nastavení prahové hodnoty a okamžitě proveďte úsudek o přetažení.
eventData.useDragThreshold
false
Prahovou hodnotu můžete přepsat nastavením na .
<summary>ドラッグの初期化処理として呼ばれます。</summary>
<param name="eventData">タッチ情報。</param>
public void OnInitializePotentialDrag(PointerEventData eventData)
{
// タッチのスライド操作を即座に発生させたいのでドラッグ開始までの閾値を無効にします
eventData.useDragThreshold = false;
}
Níže jsou uvedeny události volané při dotyku, přetažení a uvolnění.
OnPointerDown
OnDrag
Protože a , každý provádí Operate
stejné vstupní zpracování, takže vytvoříme samostatnou metodu a zavoláme ji.
OnPointerUp
Nyní jej předejte metodě a oznámit ovládacímu SendValueToControl
Vector2.zero
prvku, že přestal psá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
Metoda je základní vstupní operace D-padu.
Za prvé, dotyková poloha může být získána pomocí , ale protože tato souřadnice je souřadnice eventData.position
herní obrazovky,
RectTransformUtility.ScreenPointToLocalPointInRectangle
metoda převodu na souřadnice plátna.
Hodnoty, které mají být předány, jsou "canvas", "touch position", "camera" a " RectTransform
receiving variable".
Po získání "dotykové pozice na plátně" jej převeďte na pozici tlačítka jako počátku.
Stačí odečíst polohu ()_objectPosition
objektu.
Dále, protože dotyková pozice je stále číslo na plátně, převeďte tuto hodnotu na poměr 0 ~ 1.
Pokud vydělíte polovinou velikosti tlačítka, dotyková pozice v rozsahu tlačítka bude 0 ~ 1.
Pokud táhnete dotykem, hodnota bude 1 nebo více, protože přijímá operace i mimo tlačítko.
Vector2.ClampMagnitude
Udělejte to v metodě tak, aby nepřekročila 1.
Nakonec předejte vstupní hodnotu SendValueToControl
převedenou na 0 ~ 1 metodě.
Ovládání na obrazovce udělá zbytek za vás.
<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);
}
Připojte skript, který jste vytvořili, k tlačítku. Tato akce je nastavena tak, aby byla považována za činnost levé páčky gamepadu.
Zkuste hru posunout a dotknout se tlačítek. Myslím, že můžete vidět, že získaná hodnota se mění v závislosti na dotykové poloze. Také můžete vidět, že i když přetáhnete při dotyku, hodnota se mění v závislosti na poloze přetažení.