D-pad'i uygulamak için Ekran Denetimi'ni özelleştirme
Doğrulama ortamı
- Windows
-
- Pencereler 11
- Birlik Editörü
-
- 2020.3.25f1
- Giriş Sistemi Paketi
-
- 1.2.0
Bu ipucu için önkoşullar
Aşağıdaki ayarlar, bu ipucunun açıklaması için bir öncül olarak önceden yapılmıştır.
Aşağıdaki ipuçlarına da aşina olmalısınız:
- Oyun davranışlarına düğmeler atamak için eylem haritalarını kullanma
- Ekran Kontrolü ile dokunma için optimize edilmiş giriş kontrollerini kullanın
Ekran Kontrol Çubuğu standart yönlendirme işlemidir
Ekran Çubuğu, fiziksel bir denetleyicide bulunana benzer bir çubuğun çalışmasını çoğaltan sanal bir çubuk olarak uygulanır. Örneğin, sağa taşımak isterseniz, önce çubuğa dokunmak için ekrana dokunabilir ve ardından çubuğu aşağı indirmek için sağa kaydırabilirsiniz.
Bir çubuk işlemi olarak hayal etmek kolaydır, ancak tam tersine, hemen sağa hareket ettirmek istediğinizde, (1) dokunmak, (2) sağa kaydırmak, İki aşamalı bir işlem gerektirdiğinden, yanıt kaçınılmaz olarak biraz gecikecektir. Bu, özellikle arka arkaya hızlı bir yön değişikliği yapmanız gerektiğinde geçerlidir.
Dokunma anında yönü belirleyen yön düğmesi (standart dışı)
Hızlı yön girişi için en iyi giriş yöntemi, D-pad veya ok tuşu gibi bir şey yerleştirerek dokunma anındaki yönü belirleyebilen yöntemdir. Unity tarafından yapılmadı, ancak oyunum Little Saber'da, dokunduğunuz yönde hızlı bir şekilde hareket edebilmeniz için ok tuşlarını yerleştiriyorum. Tabii ki, hareketleri değiştirmek için dokunurken yukarı veya sola da kaydırabilirsiniz.
Bununla birlikte, Ekran Kontrolü standardının yerleştirilmesi ve uygulanması kolay değildir, çünkü yalnızca Ekran Çubukları ve Ekran Düğmeleri vardır.
Aşağıdaki şekilde gösterildiği gibi dört düğme düzenleyerek sahte bir D-pad de oluşturabilirsiniz, ancak çapraz olarak giremeyeceğiniz için sakıncalıdır. 8 düğme yerleştirirseniz, diyagonal işlem mümkündür, ancak "← ↙ ↓" gibi akış yönü işlemi hala mümkün değildir.
Ekran Kontrolü özelleştirmesiyle yön düğmesi oluşturma
Gördüğünüz gibi, Ekran Kontrolü yalnızca Çubuk ve Düğme ile standart olarak gelir, ancak eksik özellikleri kendi komut dosyalarınızla özelleştirebilirsiniz. Bu yüzden burada Ekran Kontrolü özelleştirmesi ile bir yön pedi oluşturmak istiyorum.
Eylem Haritası
Eylem haritasını kullanacağız, ancak önceki ipuçlarında oluşturulanı olduğu gibi kullanacağız, bu nedenle prosedür ihmal edildi.
Ayrıca bazı kodlar da yazdınız.
Nesneleri Konumlandırma
Girişinizi görüntülemek için bir metin alanı ve yön düğmesinin yerini alan bir düğme yerleştirin. Bu durumda, düğmeler düzenlenir, ancak bunları anlaşılması daha kolay bir görüntüyle değiştirebilirsiniz.
Girişi görüntülemek için komut dosyası
Ekran Kontrolü, dokunmayı fiziksel denetleyici etkileşimiyle değiştirdiğinden, Eylem haritası çalışırken girişinizi metin olarak görüntüleyen bir komut dosyası oluşturun.
İçerik öncekiyle aynı, bu yüzden açıklamayı atlayacağım.
- Oyun davranışlarına düğmeler atamak için eylem haritalarını kullanma
- Ekran Kontrolü ile dokunma için optimize edilmiş giriş kontrollerini kullanın
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}";
}
}
Ayarladıktan sonra, önce klavyenizle veya gamepad'inizle çalışıp çalışmadığını kontrol edin.
Ekran Kontrollerini Özelleştirme
Bu bizi bu ipuçlarının ana konusuna getiriyor.
Ekran Denetimi'ni özelleştirmek bir komut dosyasıdır, bu nedenle önce bir komut dosyası oluşturun.
Adı keyfidir, ancak bu durumda OnScreenDpad
.
Komut dosyası şöyle görünür:
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);
}
}
Customize sınıfından devralarak bir OnScreenControl
Ekran Denetimi özelleştirme sınıfı oluşturursunuz.
Ek olarak, çeşitli dokunma olaylarını almak için hedef arayüzü devralın.
Burada, "dokunurken", "dokunurken hareket ederken", "dokunma serbest bırakıldığında" ve "sürüklemeden önce" işlenir, bu nedenle sırasıyla aşağıdaki arayüzler de açıklanmaktadır.
public class OnScreenDpad
: OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Arayüz | İçeriği |
---|---|
IPointerDownHandler | Dokunulduğunda |
IPointerUpHandler | Dokunmayı bıraktığınızda |
IDragHandler | Dokunurken hareket ettiğinizde |
IInitializePotentialDragHandler | Sürüklemeye başlamadan önce |
Aşağıdaki alanlar bildirilir:
controlPathInternal
OnScreenControl
bir sınıftan devralıyorsanız gereklidir.
Giriş cihazının hangi düğmesiyle eşleneceğinin bir dizesini tutar, ancak temel olarak olduğu gibi yazabilirsiniz.
InputControl
Ancak, öznitelik korunacak değeri içermelidir (bu durumda Vektör2).
_objectPosition
_objectSizeHalf
ve düğmenin konumunu ve boyutunu önceden basılı tutun ve daha sonra hesaplamalar için kullanın.
[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;
Nesne başlatıldıktan sonra çağrılan Start
yöntem, tuval üzerindeki düğmenin konumunun ve boyutunun yarısını alır.
Boyut ayrıca ölçeği de dikkate alır.
Start
Bir yöntemle işlenir, ancak sonunda hesaplamada doğru şekilde kullanılabilirse, satın alma zamanlaması herhangi bir yerde olabilir.
// <summary>
// オブジェクトが動作する最初のタイミングで1回だけ呼ばれます。
// </summary>
private void Start()
{
var rectTransform = (RectTransform)base.transform;
// オブジェクトの位置を取得
_objectPosition = rectTransform.anchoredPosition;
// オブジェクトのサイズの半分を取得 (スケールサイズも考慮)
_objectSizeHalf = rectTransform.sizeDelta * rectTransform.localScale / 2f;
}
OnInitializePotentialDrag
dokunduktan sonra sürüklemeye başlamak istediğinizde çağrılır.
Sürüklerken, OnDrag
yöntem çağrılır.
Sürükleme kararını bir dereceye kadar önlemek için bir eşik ayarlanır, böylece parmak biraz hareket etmez ve sürükleme yargısı sadece dokunma işlemi nedeniyle gerçekleşmez.
Bu kez, ince ayar işlemi gerçekleştirmek istediğinizi varsayan bir giriş olduğundan, bu eşik ayarını devre dışı bırakın ve hemen bir sürükleme kararı verin.
eventData.useDragThreshold
false
olarak ayarlayarak eşiği geçersiz kılabilirsiniz.
<summary>ドラッグの初期化処理として呼ばれます。</summary>
<param name="eventData">タッチ情報。</param>
public void OnInitializePotentialDrag(PointerEventData eventData)
{
// タッチのスライド操作を即座に発生させたいのでドラッグ開始までの閾値を無効にします
eventData.useDragThreshold = false;
}
Aşağıda, sırasıyla dokunma, sürükleme ve serbest bırakma sırasında çağrılan olaylar verilmiştir.
OnPointerDown
OnDrag
Çünkü ve , her biri aynı giriş işlemesini gerçekleştirir Operate
, bu yüzden ayrı bir yöntem oluşturur ve çağırırız.
OnPointerUp
Şimdi, denetime yazmayı bıraktığını bildirmek için SendValueToControl
Vector2.zero
yönteme geçirin.
<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
Yöntem, çekirdek D-pad giriş işlemidir.
Her şeyden önce, dokunma pozisyonu , ile elde edilebilir, ancak bu koordinat oyun ekranının eventData.position
koordinatı olduğundan,
RectTransformUtility.ScreenPointToLocalPointInRectangle
tuval koordinatlarına dönüştürme yöntemi.
İletilecek değerler "tuval", "dokunma konumu", "kamera" ve "alıcı değişken" RectTransform
dir.
"Tuval üzerindeki dokunma konumunu" aldıktan sonra, düğmenin orijinal konumuna dönüştürün.
Sadece nesnenin konumunu ()_objectPosition
çıkarın.
Ardından, dokunma konumu hala tuval üzerinde bir sayı olduğundan, bu değeri 0 ~ 1 oranına dönüştürün.
Düğmenin boyutunu yarıya bölerseniz, düğme aralığındaki dokunma konumu 0 ~ 1 olacaktır.
Dokunarak sürüklerseniz, düğmenin dışında bile işlemleri kabul ettiği için değer 1 veya daha fazla olacaktır.
Vector2.ClampMagnitude
Bunu yöntemde, 1'i geçmeyecek şekilde yapın.
Son olarak, 0 ~ 1'e dönüştürülen giriş değerini SendValueToControl
yönteme geçirin.
Ekran Denetimi gerisini sizin yerinize halleder.
<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);
}
Oluşturduğunuz komut dosyasını düğmeye ekleyin. Bu eylem, Gamepad'in sol çubuğunun çalışması olarak kabul edilecek şekilde ayarlanmıştır.
Oyunu hareket ettirmeyi deneyin ve düğmelere dokunun. Sanırım elde edilen değerin dokunma pozisyonuna bağlı olarak değiştiğini görebilirsiniz. Ayrıca, dokunurken sürükleseniz bile, değerin sürükleme konumuna bağlı olarak değiştiğini görebilirsiniz.