Sesuaikan Kawalan Pada Skrin untuk melaksanakan pad D
Persekitaran pengesahan
- Windows
-
- Windows 11
- Penyunting Perpaduan
-
- 2020.3.25f1
- Pakej Sistem Input
-
- 1.2.0
Prasyarat untuk petua ini
Tetapan berikut telah dibuat terlebih dahulu sebagai premis untuk penerangan petua ini.
Anda juga harus biasa dengan petua berikut:
- Gunakan peta tindakan untuk memperuntukkan butang kepada tingkah laku permainan
- Gunakan kawalan input dioptimumkan sentuhan dengan Kawalan Pada Skrin
On-Screen Control Stick ialah operasi orientasi standard
Tongkat Pada Skrin dilaksanakan sebagai tongkat maya, meniru operasi tongkat yang serupa dengan yang terdapat pada pengawal fizikal. Sebagai contoh, jika anda ingin mengalihkannya ke kanan, anda boleh menyentuh skrin terlebih dahulu untuk menyentuh tongkat, dan kemudian luncurkannya ke kanan untuk mengetuk tongkat ke bawah.
Ia mudah dibayangkan sebagai operasi kayu, tetapi sebaliknya, apabila anda ingin memindahkannya ke kanan dengan serta-merta, (1) sentuh, (2) slaid ke kanan, Oleh kerana ia memerlukan operasi dua langkah, tindak balas pasti akan sedikit tertangguh. Ini benar terutamanya apabila anda perlu membuat perubahan arah yang cepat berturut-turut.
D-pad yang menentukan arah pada masa sentuhan (tidak standard)
Kaedah input terbaik untuk input arah cepat ialah kaedah yang boleh menentukan arah pada saat menyentuh dengan meletakkan sesuatu seperti pad D atau kekunci anak panah. Ia bukan dibuat oleh Unity, tetapi dalam permainan saya Little Saber, saya meletakkan kekunci anak panah supaya anda boleh bergerak dengan cepat ke arah yang anda sentuh. Sudah tentu, anda juga boleh meluncur ke atas atau ke kiri semasa menyentuh untuk menukar pergerakan.
Walau bagaimanapun, standard Kawalan Pada Skrin tidak mudah diletakkan dan dilaksanakan kerana hanya terdapat Tongkat Pada Skrin dan Butang Pada Skrin.
Anda juga boleh membuat pseudo-D-pad dengan mengatur empat butang seperti yang ditunjukkan dalam gambar di bawah, tetapi ia menyusahkan kerana anda tidak boleh memasukkan secara menyerong. Sekiranya anda meletakkan 8 butang, operasi pepenjuru mungkin, tetapi operasi arah aliran seperti "← ↙ ↓" masih tidak mungkin.
Cipta pad arah dengan penyesuaian Kawalan Pada Skrin
Seperti yang anda lihat, Kawalan Pada Skrin hanya datang standard dengan Stick and Button, tetapi anda boleh menyesuaikan ciri yang hilang dengan skrip anda sendiri. Jadi di sini saya ingin mencipta pad arah dengan penyesuaian Kawalan Pada Skrin.
Peta Tindakan
Kami akan menggunakan peta tindakan, tetapi kami akan menggunakan yang dibuat dalam petua sebelumnya seperti itu, jadi prosedur itu ditinggalkan.
Anda juga telah menulis beberapa kod.
Meletakkan objek
Letakkan kawasan teks untuk memaparkan input anda dan butang yang menggantikan pad D. Dalam kes ini, butang diatur, tetapi anda boleh menggantikannya dengan imej yang lebih mudah difahami.
Skrip untuk memaparkan input
Kerana Kawalan Pada Skrin menggantikan sentuhan dengan interaksi pengawal fizikal, Cipta skrip yang memaparkan input anda dalam teks apabila peta tindakan berfungsi.
Kandungannya sama seperti sebelumnya, jadi saya akan meninggalkan penjelasannya.
- Gunakan peta tindakan untuk memperuntukkan butang kepada tingkah laku permainan
- Gunakan kawalan input dioptimumkan sentuhan dengan Kawalan Pada Skrin
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}";
}
}
Selepas menyediakannya, mula-mula semak sama ada ia berfungsi dengan papan kekunci atau pad permainan anda.
Menyesuaikan Kawalan Pada Skrin
Ini membawa kita ke topik utama petua ini.
Menyesuaikan Kawalan Pada Skrin ialah skrip, jadi mula-mula buat skrip.
Nama itu sewenang-wenangnya, tetapi dalam kes OnScreenDpad
ini ia adalah .
Skrip kelihatan seperti ini:
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);
}
}
Anda mencipta OnScreenControl
kelas penyesuaian Kawalan Pada Skrin dengan mewarisi daripada kelas Sesuaikan.
Di samping itu, untuk menerima pelbagai acara sentuhan, mewarisi antara muka sasaran.
Di sini, "apabila menyentuh", "apabila bergerak semasa menyentuh", "apabila sentuhan dikeluarkan", dan "sebelum menyeret" diproses, jadi antara muka berikut juga diterangkan masing-masing.
public class OnScreenDpad
: OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
Kandungan | Antara Muka |
---|---|
IPointerDownHandler | Apabila disentuh |
IPointerUpHandler | Apabila anda melepaskan sentuhan |
IDragHandler | Apabila anda bergerak sambil menyentuh |
IInitializePotentialDragHandler | Sebelum anda mula menyeret |
Medan berikut diisytiharkan:
controlPathInternal
OnScreenControl
diperlukan jika anda mewarisi dari kelas.
Ia memegang rentetan butang mana peranti input untuk dipetakan, tetapi pada dasarnya anda boleh menulisnya seperti sedia ada.
InputControl
Walau bagaimanapun, atribut harus mengandungi nilai yang akan dikekalkan (Vector2 dalam kes ini).
_objectPosition
_objectSizeHalf
dan tahan separuh kedudukan dan saiz butang terlebih dahulu dan gunakannya kemudian untuk pengiraan.
[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;
Kaedah yang dipanggil Start
selepas objek dimulakan, mendapat separuh kedudukan dan saiz butang pada kanvas.
Saiz juga mengambil kira skala.
Start
Ia diproses dengan kaedah, tetapi jika ia boleh digunakan dengan betul dalam pengiraan pada akhirnya, masa pemerolehan boleh berada di mana-mana sahaja.
// <summary>
// オブジェクトが動作する最初のタイミングで1回だけ呼ばれます。
// </summary>
private void Start()
{
var rectTransform = (RectTransform)base.transform;
// オブジェクトの位置を取得
_objectPosition = rectTransform.anchoredPosition;
// オブジェクトのサイズの半分を取得 (スケールサイズも考慮)
_objectSizeHalf = rectTransform.sizeDelta * rectTransform.localScale / 2f;
}
OnInitializePotentialDrag
dipanggil apabila anda ingin mula menyeret selepas sentuhan.
Semasa menyeret, OnDrag
kaedah dipanggil.
Ambang ditetapkan untuk mengelakkan penghakiman seretan sedikit sebanyak supaya jari tidak bergerak sedikit dan penghakiman seretan tidak berlaku kerana operasi hanya menyentuh.
Kali ini, kerana ia adalah input yang menganggap bahawa anda ingin melakukan operasi penalaan halus, lumpuhkan tetapan ambang ini dan segera membuat penghakiman seretan.
eventData.useDragThreshold
false
Anda boleh mengatasi ambang dengan menetapkan kepada .
<summary>ドラッグの初期化処理として呼ばれます。</summary>
<param name="eventData">タッチ情報。</param>
public void OnInitializePotentialDrag(PointerEventData eventData)
{
// タッチのスライド操作を即座に発生させたいのでドラッグ開始までの閾値を無効にします
eventData.useDragThreshold = false;
}
Berikut ialah peristiwa yang dipanggil apabila menyentuh, menyeret dan melepaskan masing-masing.
OnPointerDown
OnDrag
Sejak dan , masing-masing Operate
melakukan pemprosesan input yang sama, jadi kami membuat kaedah yang berasingan dan memanggilnya.
OnPointerUp
Sekarang, serahkan kepada kaedah SendValueToControl
Vector2.zero
untuk memberitahu kawalan bahawa ia telah berhenti menaip.
<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
Kaedah ini adalah operasi input D-pad teras.
Pertama sekali, kedudukan sentuhan boleh didapati dengan , tetapi kerana koordinat ini adalah koordinat eventData.position
skrin permainan,
RectTransformUtility.ScreenPointToLocalPointInRectangle
kaedah untuk menukar kepada koordinat kanvas.
Nilai yang akan diluluskan ialah "kanvas", "kedudukan sentuh", "kamera", dan "menerima pembolehubah" RectTransform
.
Selepas mendapat "kedudukan sentuh pada kanvas", tukarkannya ke kedudukan butang sebagai asal.
Hanya tolak kedudukan ()_objectPosition
objek.
Seterusnya, kerana kedudukan sentuhan masih merupakan nombor pada kanvas, tukar nilai ini kepada nisbah 0 ~ 1.
Jika anda membahagikan dengan separuh saiz butang, kedudukan sentuh dalam julat butang akan menjadi 0 ~ 1.
Jika anda menyeret dengan sentuhan, nilainya akan menjadi 1 atau lebih kerana ia menerima operasi walaupun di luar butang.
Vector2.ClampMagnitude
Lakukan ini dalam kaedah supaya ia tidak melebihi 1.
Akhirnya, lulus nilai SendValueToControl
input yang ditukar kepada 0 ~ 1 kepada kaedah.
Kawalan Pada Skrin melakukan selebihnya untuk anda.
<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);
}
Lampirkan skrip yang anda buat pada butang. Tindakan ini ditetapkan untuk dianggap sebagai operasi tongkat kiri Gamepad.
Cuba gerakkan permainan dan sentuh butang. Saya fikir anda dapat melihat bahawa nilai yang diperoleh berubah bergantung pada kedudukan sentuhan. Selain itu, anda dapat melihat bahawa walaupun anda menyeret semasa menyentuh, nilai berubah bergantung pada kedudukan seret.