استخدام خرائط الإجراءات لتعيين أزرار لسلوكيات اللعبة

تحديث الصفحة :
تاريخ إنشاء الصفحة :

بيئة التحقق

نوافذ
  • ويندوز ١١
محرر الوحدة
  • 2020.3.25f1
حزمة نظام الإدخال
  • 1.2.0

المتطلبات الأساسية لهذه النصيحة

تم إجراء الإعدادات التالية مسبقا كمقدمة لوصف هذه النصيحة.

حول خرائط العمل

ذكرت برامج إدخال المستخدم على لوحات المفاتيح والفئران ولوحات الألعاب بشكل أساسي أنه تم تنفيذ إجراء معين عند الضغط على زر. في خريطة العمل ، على سبيل المثال ، يمكنك تحديد إجراء "القفز" وتعيين أزرار وحدة التحكم ومفاتيح لوحة المفاتيح له. نتيجة لذلك ، يحتاج البرنامج فقط إلى وصف العملية عند تنفيذ إجراء معين. حتى إذا قمت بتعيين زر على وحدة تحكم أخرى كفكرة لاحقة ، يمكنك تطبيقه دون تغيير برنامج التشغيل.

إنشاء خريطة عمل

هنا ، أود إنشاء خريطة عمل وعرض معلومات إدخال المستخدم في النص. هناك عدة طرق للحصول على مدخلات المستخدم باستخدام خرائط العمل.

انقر بزر الماوس الأيمن فوق أي مجلد في المشروع لإنشاء إجراء إدخال. موقع المجلد المراد إنشاؤه تعسفي ، ولكن يرجى إدارته وفقا لمشروعك. اسم الملف تعسفي أيضا ، ولكن ها InputActionSample هو .

عند النقر نقرا مزدوجا فوق الملف الذي تم إنشاؤه ، سيتم عرض النافذة التالية.

أولا ، انقر فوق الزر + في خرائط العمل لإنشاء خريطة عمل. كوحدة إنشاء ، إذا تغير محتوى العملية اعتمادا على المشهد ، تعريفه في تلك الوحدة. على سبيل المثال ، في حالة لعبة حركة التمرير الجانبي ، تتغير محتويات العملية أثناء الإجراء وفي القائمة ، لذلك ستقوم بإنشاء خريطة عمل لكل منها.

هنا ، على سبيل المثال ، نحدد إجراء التمرير الجانبي ونسميه "SideScrollActionMap".

بعد ذلك ، قم بإنشاء إجراءات. نظرا لأنها عينة ، فلن أقوم بعمل الكثير منها ، ولكن هنا سننشئ إجراءات "نقل" للحركة و "هجوم" للهجوم. نظرا لأنه تم إنشاء اسم بالفعل ، يرجى تغيير الاسم أو إنشاء اسم جديد ، انقر فوق الزر + في الزاوية اليمنى العليا وأدخله.

أولا ، قم بتكوين تكوين النقل. تفترض وحدة التحكم أنك تستخدم مفاتيح العصا ولوحة الاتجاهات ومؤشر لوحة المفاتيح. في حالة إجراء التمرير الجانبي ، هناك حالات يتم فيها استخدام اليسار واليمين فقط ، ولكن هنا نفترض أنك تستخدم أربعة اتجاهات تفكر في القفز باستخدام المفتاح العلوي والرابض باستخدام المفتاح السفلي.

عند تحديد نقل ، يوجد تحديد نوع الإجراء على اليمين ، لذا اضبط هذا على "القيمة".

سترى نوع التحكم أدناه ، لذا حدد Vector2. وذلك لأن الجزء العلوي والسفلي يتم تعيينهما إلى Y ، ويتم تعيين اليسار واليمين إلى X.

ثم حدد المفتاح الذي تريد تعيينه لهذا الحدث. حدد بلا ربط في المنتصف وحدد مسار على اليمين. هنا نختار عصا GamePad اليسرى.

هذا يربط العصا اليسرى ل GamePad بهذه الخطوة.

لربط وحدات التحكم الأخرى أيضا ، حدد "إضافة ربط" من الزر + على يمين نقل.

الآن بعد أن تمت إضافة No Binding ، نقوم بتعيين Dpad ل GamePad.

بهذه الطريقة ، يمكنك إضافة نوع وحدة التحكم التي تريد دعمها ، بالإضافة إلى المفاتيح والعصي. من الممكن أيضا تعيينه خصيصا لوحدة تحكم ألعاب معينة.

العصي و Dpads هي أزرار تفترض لأعلى ولأسفل ولليسار ولليمين ، بحيث يمكن إضافتها مع هذا ، ولكن في حالة لوحات المفاتيح ، كلها مفاتيح فردية ، لذلك لا يوجد تعريف لأعلى ولأسفل ولليسار ولليمين. لضبط لوحة المفاتيح لأعلى أو لأسفل أو لليسار أو لليمين، حدد إضافة لأعلى لأسفل يسار يمين مركب من الزر +.

سيتم بعد ذلك إضافة 2D Vector ويمكنك تعيينه لكل من أعلى أسفل اليسار الأيمن ، كما هو موضح في الشكل أدناه.

على سبيل المثال ، إذا كنت تستخدم Up ، فقم بتعيين "سهم لأعلى" على لوحة المفاتيح. بالمناسبة ، إذا كنت مزعجا للعثور على مفتاح ، فيمكنك تحديده بسهولة عن طريق الضغط على المفتاح الهدف أثناء النقر فوق الزر "استمع".

تم الآن تعيين Up على سهم لأعلى.

وبالمثل ، قم بتعيين لأسفل ولليسار ولليمين وبذلك تكون قد انتهيت.

بالطبع ، لا يمكن تعيين مفاتيح المؤشر فحسب ، بل يمكن أيضا تعيين WASD.

بعد ذلك ، قم بتكوين الهجوم. من السهل تعيين الهجوم لأنه زر واحد. أولا ، حدد هجوم وتأكد من أن نوع الإجراء هو زر.

ثم حدد بلا ربط وحدد الزر الذي تريد تعيينه من المسار.

إذا كنت ترغب في إضافة المزيد ، فحدد "إضافة ربط" من الزر +.

أضف ما تحتاج إليه. نظرا لأنه يتم التعامل معها كزر ، يمكن ضبط لوحة المفاتيح بنفس طريقة ضبط وحدة التحكم في الألعاب.

عند اكتمال جميع الإعدادات ، انقر فوق "حفظ الأصل" للحفظ. يمكنك إغلاق هذه النافذة.

أخيرا ، باستخدام ملف Inputactions الخاص بالمشروع (في هذه الحالة ، ملف InputActionSample الذي قمت بإنشائه مسبقا) ، حدد "إنشاء فئة C #" في المفتش. ستتم إضافة المعلمة ، ولكن انقر فوق الزر "تطبيق" كما هو.

سيؤدي هذا إلى إنشاء ملف نصي بنفس الاسم. أنه يحتوي على فئات مفيدة لاستخدام خرائط العمل من البرامج.

كيفية تلقي معلومات الإدخال

هناك عدة طرق لتلقي المدخلات بناء على خريطة الإجراءات. تشرح هذه النصيحة ثلاثة أنماط ، ولكن من الأفضل التركيز على أحدها عند صنع لعبة بالفعل. إذا كنت تستخدمها بشكل منفصل ، فسيكون من الصعب إدارتها.

أيضا، إذا كنت تستخدم طرق تلقي إدخال متعددة في مشهد واحد، قد تتعارض المعالجة داخليا ولا تعمل بشكل صحيح.

تلقي معلومات الإدخال في إرسال الرسائل

الطريقة الأولى هنا هي كيفية تلقي معلومات الإدخال في "إرسال الرسائل".

هذه المرة ، أريد عرض المعلومات المدخلة في النص ، لذلك سأضع كائنا نصيا.

أيضا ، نظرا لأن هذه النصيحة ستحاول الحصول على معلومات إدخال متعددة ، فسنقوم بإنشاء كائن فارغ لتعيين المكون بشكل منفصل. يمكن أن يكون الاسم أي شيء.

بعد ذلك ، أضف مكون إدخال اللاعب إلى الكائن الفارغ. يعد إدخال اللاعب مكونا مهما لربط خرائط الحركة والبرامج النصية.

في "إضافة مكون" ، يوجد "إدخال لاعب" في فئة "الإدخال" ، لذا قم بإضافته.

بمجرد إضافة مكون إدخال اللاعب ، قم بتعيين خريطة الإجراء التي أنشأتها في "الإجراءات". قم بإفلاته من المشروع أو حدده من أيقونة + إلى اليمين.

تحقق من أن الخريطة الافتراضية هي الخريطة التي أنشأتها في خريطة الإجراءات.

تحقق من أن السلوك هو "إرسال رسائل".

بعد ذلك ، قم بإنشاء برنامج نصي. يمكن أن يكون اسم الملف أي شيء ، ولكن ها InputSendMessage هو .

يبدو البرنامج النصي كما يلي:

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class InputSendMessage : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  /// <summary>
  /// Move アクションが実行されたときに呼ばれる。
  /// </summary>
  /// <param name="inputValue">入力量。</param>
  public void OnMove(InputValue inputValue)
  {
    var vec = inputValue.Get<Vector2>();
    TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
  }

  /// <summary>
  /// Attack アクションが実行されたときに呼ばれる。
  /// </summary>
  public void OnAttack(InputValue inputValue)
  {
    TextObject.text = $"Attack:{inputValue.isPressed}\n{TextObject.text}";
  }
}
  • يحتوي الكائن على إدخال مشغل مرفق يقوم بتعيين إرسال الرسائل
  • الوراثة من السلوك الأحادي

إذا تم استيفاء الشروط ، ثم إذا قمت بتعريف طريقة تسمى "OnXXXXXXXX" ، سيتم استدعاء الطريقة المستهدفة عند تنفيذ عملية الإجراء المحددة. "XXXXXXXX" هو اسم الإجراءات التي تم إنشاؤها في خريطة الإجراءات. هنا ، أنشأنا إجراءات "نقل" و "هجوم" ، لذا فإن أسماء الطرق هي "OnMove" و "OnAttack" ، على التوالي.

OnMove يمكنك الحصول على المبلغ الذي تم إدخاله من وسيطة InputValue . نظرا لتعيين نوع عنصر التحكم على "Vector 2" ، سيتم استلام قيمة InputValue.Get<Vector2> الإدخال في .

OnAttackInputValue.isPressed يمكنك معرفة ما إذا كنت تضغط أيضا.

بعد حفظ البرنامج النصي، قم بإرفاقه بكائن يحتوي على مكون إدخال مشغل. قم بتعيين كائن النص للعرض أيضا.

قم بتشغيل اللعبة وإلقاء نظرة. هذه المرة ، قمت بتضمين تعريف لوحة الألعاب ولوحة المفاتيح ، لذلك يجب أن تعمل بغض النظر عن أي واحد تعمل.

كما ترى عند نقله ، يمكنك أن ترى أن الطريقة تسمى فقط عندما يكون هناك تغيير في القيمة من الحالة السابقة. على سبيل المثال ، أثناء تحريك العصا إلى اليسار ، يطلق عليها أحادية التفكير ، ولكن ليس إلى اليسار (- OnMove 1,0). OnMove يستجيب زر الهجوم أيضا فقط في اللحظة التي يتم الضغط عليه فيها ، وإذا تم الضغط عليه مع الاستمرار ، فلن يتم استدعاء الطريقة.

لذلك ، أعتقد أن الاستخدام المثالي ليس إجراء معالجة اللعبة عند استدعاء OnXXXXXXXX ، ولكن الاحتفاظ بمحتويات الإدخال فقط واستخدام هذه القيم في معالجة تحديث اللعبة.

بالمناسبة ، في الحالة الحالية ، لا يتم استدعاؤه عند تحرير الزر ، لذلك لا يمكن تحديد وقت OnAttack تحرير الزر. للرد على هذا ، حدد إجراء الهجوم الذي يحدد الزر في إعدادات خريطة الإجراءات وأضف "Press" من "التفاعلات". بعد ذلك ، اضبط سلوك الزناد للضغط المضاف على "Press And Release" واحفظه.

عند التنفيذ ، يمكنك أن ترى أنه يسمى حتى OnAttack عند تحرير الزر. isPressed false نظرا لأنه يصبح ، فمن الممكن أيضا تحديد ما إذا كان هذا هو توقيت الإصدار.

بالمناسبة ، يرجى حذف هذا التفاعل لأنه لن يتم استخدامه في المستقبل.

تلقي المدخلات مع استدعاء أحداث الوحدة

الطريقة الثانية لتلقي المدخلات هي استدعاء أحداث الوحدة ، لذلك دعونا نجرب ذلك. كما ذكر أعلاه ، يمكن أن يؤدي استخدام طرق إدخال متعددة إلى معالجة متضاربة ، لذلك إذا تم تمكين معالجة أخرى ، فقم بتعطيلها.

أولا ، ضع كائن النص بحيث يمكن عرض معلومات الإدخال.

يؤدي استدعاء أحداث الوحدة إلى إنشاء كائن فارغ يقوم بتنفيذ العمليات ذات الصلة.

أضف إدخال > إدخال Player إلى الكائن الفارغ.

قم بتعيين ملف خريطة الإجراء الذي أنشأته للإجراءات (في هذه الحالة، InputActionSample) وقم بتعيين خريطة الإجراءات التي قمت بإنشائها (في هذه الحالة، SideScrollActionMap) إلى الخريطة الافتراضية. قم بتعيين السلوك لاستدعاء أحداث الوحدة.

إنشاء برنامج نصي. الاسم تعسفي ، لكنه في هذه الحالة InputInvokeUnityEvents .

يبدو البرنامج النصي كما يلي:

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class InputInvokeUnityEvents : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  /// <summary>
  /// Move 操作を行ったときに呼ばれる。
  /// </summary>
  /// <param name="context">コールバック内容。</param>
  public void OnMove(InputAction.CallbackContext context)
  {
    var vec = context.ReadValue<Vector2>();
    TextObject.text = $"Move:({vec.x:f2}, {vec.y:f2})\n{TextObject.text}";
  }

  /// <summary>
  /// Move 操作を行ったときに呼ばれる。
  /// </summary>
  /// <param name="context">コールバック内容。</param>
  public void OnAttack(InputAction.CallbackContext context)
  {
    var value = context.ReadValueAsButton();
    TextObject.text = $"Attack:{value}\n{TextObject.text}";
  }
}

اسم OnMoveOnAttack الطريقة الذي يتم استدعاؤه عندما يتفاعل المستخدم معه هو ، كما في حالة إرسال الرسائل. في استدعاء أحداث الوحدة ، يمكنك تعيين اسم هذه الطريقة كما تريد.

عندما يتم استدعاء كل منها ، يتم تمريرها كوسيطة InputAction.CallbackContext ، حتى تتمكن من الحصول على حالة الإدخال من هناك. إذا قمت بتعيين "قيمة" في الإجراء ، فيمكنك استلامها في الطريقة ، وإذا قمت ReadValue بتعيين ReadValueAsButton "زر" ، فيمكنك استلامها في الطريقة.

بعد حفظ البرنامج النصي ، قم بإرفاق إدخال Player بالكائن الذي تقوم بإعداده وقم بتعيين كائن نص العرض.

بعد ذلك ، قم بتوسيع "الحدث" و "اسم خريطة العمل (SideScrollActionMap)" في إدخال اللاعب وسترى الإجراءات "نقل" و "هجوم" التي قمت بإنشائها.

أولا ، انقر فوق الزر + على تحرك لإضافته.

الكائن الموجود في الزاوية اليسرى السفلية هو الكائن الخاص بك ، ويتم تعيين الوظيفة على الطريقة التي أنشأتها OnMove للتو.

قم بتكوين حدث الهجوم أيضا.

قم بتشغيل اللعبة لترى كيف تعمل.

في الأساس ، يتم استدعاؤه فقط عندما تتغير نفس قيمة إرسال الرسائل ، ولكن لسبب ما قد يتم استدعاء الطريقة مرتين في نفس الوقت. لا أعرف السبب ، لكنني أعتقد أنه ربما يرجع إلى أن عملية البدء والعملية المستمرة تعمل في نفس الوقت. ومع ذلك ، أعتقد أنه لا توجد مشكلة إذا احتفظت بالقيمة المدخلة فقط كما في حالة إرسال الرسائل وقمت بإجراء معالجة اللعبة الفعلية بشكل منفصل في عملية التحديث.

استخدام برنامج نصي تم إنشاؤه تلقائيا لتلقي معلومات الإدخال

يصف القسم الثالث كيفية الحصول على معلومات الإدخال باستخدام برنامج نصي تم إنشاؤه من ملف خريطة إجراء.

نظرا لوجود احتمال حدوث تعارض مع عمليات الاستحواذ الأخرى ، يرجى تعطيل عمليات الاستحواذ الأخرى.

ضع كائن نصي لعرض معلومات الإدخال.

أيضا، قم بإنشاء كائن فارغ لاسترداد معلومات الإدخال. تستخدم هذه المقالة نصا برمجيا تم إنشاؤه تلقائيا، لذا لا تحتاج إلى إضافة إدخال المشغل.

البرنامج النصي الذي يتم إنشاؤه تلقائيا من خريطة الإجراءات هو مجرد مكتبة ، لذا قم بإنشاء برنامج نصي منفصل لعنصر التحكم. الاسم تعسفي ، لكنه في هذه الحالة InputScript .

يبدو البرنامج النصي كما يلي:

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class InputScript : MonoBehaviour
{
  /// <summary>情報を表示させるテキストオブジェクト。</summary>
  [SerializeField] private Text TextObject;

  /// <summary>アクションマップから自動生成されたクラス。</summary>
  private InputActionSample _actionMap;

  private void Awake()
  {
    // 各操作を行ったときに呼ばれるイベントを設定する
    _actionMap = new InputActionSample();
    _actionMap.SideScrollActionMap.Move.performed += context => OnMove(context);
    _actionMap.SideScrollActionMap.Attack.performed += 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}";
  }
}

حدد فئة InputActionSample تم إنشاؤها تلقائيا من خريطة الإجراءات في الحقل. تحدد هذه الفئة كل مجموعة إجراءات في خريطة الإجراءات، ويمكنك تعيين الأحداث التي يتم استدعاؤها عند تنفيذ هذه الإجراءات.

Awake في الطريقة ، InputActionSample يتم إنشاء مثيل وتعيين الحدث الذي تم استدعاؤه في وقت الإجراء. عند OnMoveتنفيذ هذه العمليات، يتم الآن استدعاء الأسلوب , OnAttack .

ومع ذلك ، نظرا لأننا قمنا بتعيين الحدث هنا فقط ، نحتاج OnEnable إلى استدعاء الطريقة عند Enable استدعائها لتمكين خريطة الإجراء.

أيضا ، نظرا لأنه يتم التعامل مع سلوك إدخال المستخدم على أنه عملية عالمية ، لمنع OnDisable خريطة العمل من القيام بعمل إضافي بعد إبطال هذا الكائن ، نسمي الطريقة في Disable الطريقة لتعطيله.

بعد حفظ البرنامج النصي ، قم بإرفاقه بالكائن الفارغ الذي قمت بإنشائه وقم بتعيين كائن النص للعرض.

قم بتشغيل اللعبة لترى كيف تعمل.

كما ترى ، لا يتم استدعاء الطريقة عندما OnMove تصبح عملية النقل (0 ، 0). لست متأكدا من السبب ، ولكن يبدو أن الحدث الذي تم تنفيذه يأخذ فقط الحدث الذي تم تمكين ضغطات المفاتيح عليه.

بالمناسبة ، إذا لم تقم بتعيين التفاعلات في خريطة الإجراء للهجوم ، فلن يتم استدعاؤها عند OnAttack تحرير الزر.

للتعامل canceled مع هذا ، تحتاج إلى إعداد حدث. إذا كنت لا ترغب في إجراء معالجة خاصة عند (0 ، 0) ، يمكنك استدعاء الطريقة كما هي OnMove . وينطبق الشيء نفسه على الهجوم.

private void Awake()
{
  // 各操作を行ったときに呼ばれるイベントを設定する
  _actionMap = new InputActionSample();
  _actionMap.SideScrollActionMap.Move.performed += context => OnMove(context);
  _actionMap.SideScrollActionMap.Attack.performed += context => OnAttack(context);
  _actionMap.SideScrollActionMap.Move.canceled += context => OnMove(context);       // 追加
  _actionMap.SideScrollActionMap.Attack.canceled += context => OnAttack(context);   // 追加
}

قم بتشغيل وتحقق من ظهور Move:(0, 0) أو Attack:False .