ڈی پیڈ کو نافذ کرنے کے لئے آن اسکرین کنٹرول کو اپنی مرضی کے مطابق بنائیں

جب صفحے کی تازہ کاری :
صفحہ تخلیق تاریخ :

تصدیق کا ماحول

Windows
  • ونڈوز 11
یونٹی ایڈیٹر
  • 2020.3.25f1
ان پٹ سسٹم پیکیج
  • 1.2.0

اس ٹوٹکے کے لئے ضروری شرائط

مندرجہ ذیل ترتیبات اس ٹپ کی وضاحت کے لئے بنیاد کے طور پر پیشگی بنائی گئی ہیں۔

آپ کو مندرجہ ذیل تجاویز سے بھی واقف ہونا چاہئے:

آن اسکرین کنٹرول اسٹک معیاری اوریئنٹیشن آپریشن ہے

آن اسکرین اسٹک کو ورچوئل اسٹک کے طور پر نافذ کیا جاتا ہے ، جو جسمانی کنٹرولر پر پائے جانے والے چھڑی کے آپریشن کی نقل کرتا ہے۔ مثال کے طور پر ، اگر آپ اسے دائیں طرف منتقل کرنا چاہتے ہیں تو ، آپ پہلے چھڑی کو چھونے کے لئے اسکرین کو چھو سکتے ہیں ، اور پھر چھڑی کو نیچے گرانے کے لئے اسے دائیں طرف سلائیڈ کرسکتے ہیں۔

چھڑی کے آپریشن کے طور پر تصور کرنا آسان ہے ، لیکن اس کے برعکس ، جب آپ اسے فوری طور پر دائیں طرف منتقل کرنا چاہتے ہیں تو ، (1) ٹچ کریں ، (2) دائیں طرف سلائڈ کریں ، چونکہ اس کے لئے دو مراحل کے آپریشن کی ضرورت ہوتی ہے ، لہذا جواب لازمی طور پر تھوڑا تاخیر کا شکار ہوگا۔ یہ خاص طور پر سچ ہے جب آپ کو ایک قطار میں سمت کی فوری تبدیلی کرنے کی ضرورت ہوتی ہے۔

ڈی پیڈ جو چھونے کے وقت سمت کا تعین کرتا ہے (غیر معیاری)

فوری سمت ان پٹ کے لئے بہترین ان پٹ طریقہ وہ ہے جو چھونے کے وقت سمت کا تعین ڈی پیڈ یا تیر کلید جیسی کسی چیز کو رکھ کر کرسکتا ہے۔ یہ یونٹی کے ذریعہ نہیں بنایا گیا ہے ، لیکن میرے کھیل لٹل سیبر میں ، میں تیر کی چابیاں رکھتا ہوں تاکہ آپ تیزی سے اس سمت میں آگے بڑھ سکیں جس کو آپ چھوتے ہیں۔ یقینا ، آپ حرکات کو تبدیل کرنے کے لئے چھوتے وقت اوپر یا بائیں بھی سلائڈ کرسکتے ہیں۔

تاہم ، آن اسکرین کنٹرول اسٹینڈرڈ کو رکھنا اور نافذ کرنا آسان نہیں ہے کیونکہ صرف آن اسکرین اسٹک اور آن اسکرین بٹن موجود ہیں۔

جیسا کہ نیچے دی گئی تصویر میں دکھایا گیا ہے ، آپ چار بٹنوں کو ترتیب دے کر ایک جعلی ڈی پیڈ بھی بنا سکتے ہیں ، لیکن یہ غیر آسان ہے کیونکہ آپ کونے میں ان پٹ نہیں کرسکتے ہیں۔ اگر آپ 8 بٹن رکھتے ہیں تو ، ڈائیگنل آپریشن ممکن ہے ، لیکن بہاؤ کی سمت کا آپریشن جیسے "← ↙ π " اب بھی ممکن نہیں ہے۔

آن اسکرین کنٹرول تخصیص کے ساتھ ایک ڈائریکشنل پیڈ بنائیں

جیسا کہ آپ دیکھ سکتے ہیں ، آن اسکرین کنٹرول صرف اسٹک اور بٹن کے ساتھ معیاری آتا ہے ، لیکن آپ گمشدہ خصوصیات کو اپنے اسکرپٹ کے ساتھ اپنی مرضی کے مطابق کرسکتے ہیں۔ لہذا یہاں میں آن اسکرین کنٹرول تخصیص کے ساتھ ایک ڈائریکشنل پیڈ بنانا چاہتا ہوں۔

ایکشن کا نقشہ

ہم ایکشن میپ کا استعمال کریں گے ، لیکن ہم پچھلے ٹپس میں بنائے گئے ایک کو اسی طرح استعمال کریں گے جیسے یہ ہے ، لہذا طریقہ کار کو خارج کردیا گیا ہے۔

آپ نے کچھ کوڈ بھی لکھا ہے.

پوزیشننگ آبجیکٹ

اپنے ان پٹ کو ظاہر کرنے کے لئے ایک ٹیکسٹ ایریا رکھیں اور ایک بٹن جو ڈی پیڈ کی جگہ لے۔ اس صورت میں ، بٹنوں کو ترتیب دیا گیا ہے ، لیکن آپ انہیں ایک ایسی تصویر کے ساتھ تبدیل کرسکتے ہیں جو سمجھنے میں آسان ہو۔

ان پٹ ظاہر کرنے کے لئے اسکرپٹ

کیونکہ آن اسکرین کنٹرول ٹچ کو جسمانی کنٹرولر تعامل سے تبدیل کرتا ہے، ایک اسکرپٹ بنائیں جو متن میں آپ کے ان پٹ کو ظاہر کرتا ہے کیونکہ ایکشن نقشہ کام کرتا ہے۔

مواد پہلے کی طرح ہی ہے، لہذا میں وضاحت کو چھوڑ دوں گا.

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}";
  }
}

اسے ترتیب دینے کے بعد ، پہلے چیک کریں کہ آیا یہ آپ کے کی بورڈ یا گیم پیڈ کے ساتھ کام کرتا ہے۔

آن اسکرین کنٹرولز کو اپنی مرضی کے مطابق بنانا

یہ ہمیں ان تجاویز کے اہم موضوع پر لاتا ہے. آن اسکرین کنٹرول کو اپنی مرضی کے مطابق بنانا ایک اسکرپٹ ہے ، لہذا پہلے اسکرپٹ بنائیں۔ نام من مانی ہے، لیکن اس معاملے OnScreenDpad میں یہ ہے.

اسکرپٹ اس طرح نظر آتا ہے:

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);
  }
}

آپ اپنی مرضی کے OnScreenControl مطابق کلاس سے وراثت میں حاصل کرکے آن اسکرین کنٹرول کسٹمائزیشن کلاس بناتے ہیں۔ اس کے علاوہ ، مختلف ٹچ ایونٹس حاصل کرنے کے لئے ، ہدف انٹرفیس کو وراثت میں لیں۔ یہاں ، "چھوتے وقت"، "چھوتے وقت حرکت کرتے وقت"، "جب چھونا جاری ہوتا ہے"، اور "گھسیٹنے سے پہلے" پر عمل کیا جاتا ہے، لہذا مندرجہ ذیل انٹرفیس بھی بالترتیب بیان کیے جاتے ہیں۔

public class OnScreenDpad
  : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler, IInitializePotentialDragHandler
انٹرفیس کے مندرجات
IPointerDownHandler جب چھویا جاتا ہے
IPointerUpHandler جب آپ ٹچ جاری کرتے ہیں
IDragHandler جب آپ چھوتے وقت حرکت کرتے ہیں
IInitializePotentialDragHandler اس سے پہلے کہ آپ گھسیٹنا شروع کریں

درج ذیل شعبوں کا اعلان کیا گیا ہے:

controlPathInternalOnScreenControl اگر آپ کسی کلاس سے وراثت میں ملے تو ضروری ہے. اس میں نقشہ بنانے کے لئے ان پٹ ڈیوائس کے کس بٹن کی ایک تار ہوتی ہے ، لیکن بنیادی طور پر آپ اسے اسی طرح لکھ سکتے ہیں جیسے یہ ہے۔ InputControl تاہم ، صفت کو برقرار رکھنے کے لئے قیمت پر مشتمل ہونا چاہئے (اس معاملے میں ویکٹر 2)۔

_objectPosition_objectSizeHalf اور بٹن کی آدھی پوزیشن اور سائز کو پیشگی پکڑیں اور اسے بعد میں حساب کتاب کے لئے استعمال کریں۔

[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;

آبجیکٹ کو شروع کرنے کے بعد کہا جانے Start والا طریقہ ، کینوس پر بٹن کی آدھی پوزیشن اور سائز حاصل کرتا ہے۔ سائز پیمانے کو بھی مدنظر رکھتا ہے۔ Start اس پر ایک طریقہ کار کے ذریعہ عمل کیا جاتا ہے ، لیکن اگر اسے آخر میں حساب کتاب میں صحیح طریقے سے استعمال کیا جاسکتا ہے تو ، حصول کا وقت کہیں بھی ہوسکتا ہے۔

// <summary>
// オブジェクトが動作する最初のタイミングで1回だけ呼ばれます。
// </summary>
private void Start()
{
  var rectTransform = (RectTransform)base.transform;

  // オブジェクトの位置を取得
  _objectPosition = rectTransform.anchoredPosition;

  // オブジェクトのサイズの半分を取得 (スケールサイズも考慮)
  _objectSizeHalf = rectTransform.sizeDelta * rectTransform.localScale / 2f;
}

OnInitializePotentialDrag اسے اس وقت کہا جاتا ہے جب آپ چھونے کے بعد گھسیٹنا شروع کرنا چاہتے ہیں۔ گھسیٹتے وقت، OnDrag طریقہ کہا جاتا ہے. ڈریگ فیصلے کو کسی حد تک روکنے کے لئے ایک حد مقرر کی گئی ہے تاکہ انگلی تھوڑی سی حرکت نہ کرے اور صرف چھونے کے عمل کی وجہ سے ڈریگ فیصلہ نہ ہو۔

اس بار ، چونکہ یہ ایک ان پٹ ہے جو فرض کرتا ہے کہ آپ فائن ٹیوننگ آپریشن کرنا چاہتے ہیں ، لہذا اس حد کی ترتیب کو غیر فعال کریں اور فوری طور پر ڈریگ فیصلہ کریں۔ eventData.useDragThreshold false آپ حد مقرر کرکے حد سے تجاوز کرسکتے ہیں۔

/// <summary>ドラッグの初期化処理として呼ばれます。</summary>
/// <param name="eventData">タッチ情報。</param>
public void OnInitializePotentialDrag(PointerEventData eventData)
{
  // タッチのスライド操作を即座に発生させたいのでドラッグ開始までの閾値を無効にします
  eventData.useDragThreshold = false;
}

ذیل میں وہ واقعات ہیں جنہیں بالترتیب چھونے ، گھسیٹنے اور چھوڑنے پر کہا جاتا ہے۔ OnPointerDown OnDrag چونکہ اور ، ہر ایک ایک ہی ان پٹ پروسیسنگ انجام دیتا ہے Operate ، لہذا ہم ایک علیحدہ طریقہ بناتے ہیں اور اسے کال کرتے ہیں۔ OnPointerUp اب ، اسے کنٹرول کو مطلع کرنے کے طریقہ SendValueToControl Vector2.zero کار پر پاس کریں کہ اس نے ٹائپنگ بند کردی ہے۔

/// <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 یہ طریقہ کور ڈی پیڈ ان پٹ آپریشن ہے۔

سب سے پہلے ، ٹچ پوزیشن کے ساتھ حاصل کیا جاسکتا ہے ، لیکن چونکہ یہ کوآرڈینیٹ گیم اسکرین کا eventData.position کوآرڈینیٹ ہے ، RectTransformUtility.ScreenPointToLocalPointInRectangle کینوس کوآرڈینیٹس میں تبدیل کرنے کا طریقہ۔ پاس کی جانے والی اقدار "کینوس"، "ٹچ پوزیشن"، " RectTransformکیمرہ"، اور "متغیر وصول کرنا" ہیں۔

"کینوس پر ٹچ پوزیشن" حاصل کرنے کے بعد ، اسے اصل کے طور پر بٹن کی پوزیشن میں تبدیل کریں۔ صرف آبجیکٹ کی پوزیشن () کو کم کریں_objectPosition۔

اگلا ، چونکہ ٹچ پوزیشن اب بھی کینوس پر ایک نمبر ہے ، لہذا اس قدر کو 0 ~ 1 کے تناسب میں تبدیل کریں۔ اگر آپ بٹن کے سائز کو آدھے سے تقسیم کرتے ہیں تو ، بٹن کی حد کے اندر ٹچ پوزیشن 0 ~ 1 ہوگی۔ اگر آپ ٹچ کے ساتھ گھسیٹتے ہیں تو ، قیمت 1 یا اس سے زیادہ ہوگی کیونکہ یہ بٹن کے باہر بھی کارروائیوں کو قبول کرتا ہے۔ Vector2.ClampMagnitude طریقہ کار میں ایسا کریں تاکہ یہ 1 سے زیادہ نہ ہو۔

آخر میں ، ان پٹ ویلیو SendValueToControl کو طریقہ کار میں 0 ~ 1 میں تبدیل کریں۔ آن اسکرین کنٹرول آپ کے لئے باقی کام کرتا ہے۔

/// <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);
}

اپنے بنائے ہوئے اسکرپٹ کو بٹن سے منسلک کریں۔ اس عمل کو گیم پیڈ کی بائیں چھڑی کے آپریشن کے طور پر سمجھا جائے گا۔

کھیل کو منتقل کرنے کی کوشش کریں اور بٹنوں کو چھوئیں۔ مجھے لگتا ہے کہ آپ دیکھ سکتے ہیں کہ حاصل کردہ قدر ٹچ پوزیشن پر منحصر ہے۔ اس کے علاوہ ، آپ دیکھ سکتے ہیں کہ اگر آپ چھوتے وقت گھسیٹتے ہیں تو بھی ، قیمت ڈریگ پوزیشن پر منحصر ہوتی ہے۔