استفاده از نقشههای کنش برای اختصاص دکمهها به رفتارهای بازی

صفحه به روز شده :
تاریخ ایجاد صفحه :

محیط تایید

ویندوز
  • ویندوز 11
ویرایشگر یونیتی
  • دانلود: 2020.3.25f1
بسته سیستم ورودی
  • 1.2.0

پیشنیازهای این نکته

تنظیمات زیر از قبل به عنوان یک فرض برای توصیف این نکته ساخته شده است.

درباره نقشه های اکشن

برنامه های ورودی کاربر در صفحه کلید، موش ها و گیم پد ها اساسا اظهار داشتند که یک عمل خاص زمانی انجام می شود که یک دکمه فشار داده می شود. به عنوان مثال، در نقشه عمل، شما می توانید عمل "پریدن" را تعریف کنید و دکمه های کنترل کننده و کلید های صفحه کلید را به ان اختصاص دهید. در نتیجه، برنامه تنها نیاز به توصیف فرایند زمانی دارد که یک عمل خاص انجام شود. حتی اگر یک دکمه را به عنوان یک فکر بعدی به کنترل کننده دیگری اختصاص دهید، می توانید ان را بدون تغییر برنامه عملیاتی اعمال کنید.

ایجاد یک Action Map

در اینجا، من می خواهم یک نقشه عمل ایجاد کنم و اطلاعات ورودی کاربر را در متن نمایش دهم. راه های مختلفی برای دریافت ورودی کاربر با استفاده از نقشه های اکشن وجود دارد.

روی هر پوشه در پروژه کلیک راست کنید تا یک عمل ورودی ایجاد شود. محل پوشه ای که باید ایجاد شود خودسرانه است، اما لطفا ان را با توجه به پروژه خود مدیریت کنید. نام فایل نیز خودسرانه است، اما در اینجا InputActionSample ان است.

هنگامی که روی فایل ایجاد شده دوبار کلیک می کنید، پنجره زیر نمایش داده می شود.

ابتدا روی دکمه + در Action Maps کلیک کنید تا یک نقشه اکشن ایجاد کنید. به عنوان یک واحد ایجاد، اگر محتوای عملیات بسته به صحنه تغییر کند، در ان واحد تعریف خواهد شد. به عنوان مثال، در مورد یک بازی اکشن پیمایش جانبی، محتویات عملیات در طول عمل و در منو تغییر می کند، بنابراین شما یک نقشه اکشن برای هر یک ایجاد می کنید.

در اینجا، به عنوان مثال، ما یک عمل پیمایش جانبی را تعریف می کنیم و ان را "SideScrollActionMap" می نامیم.

بعد، ایجاد اقدامات. از انجا که این یک نمونه است، من بسیاری از انها را نمی خواهم، اما در اینجا ما اقدامات "حرکت" را برای حرکت و "حمله" برای حمله ایجاد خواهیم کرد. از انجا که یکی از انها قبلا ایجاد شده است، لطفا نام را تغییر دهید یا یک نام جدید ایجاد کنید، روی دکمه + در گوشه بالا سمت راست کلیک کنید و ان را وارد کنید.

ابتدا پیکربندی Move را پیکربندی کنید. کنترل کننده فرض می کند که شما از کلیدهای مکان نما چوب، D-pad و صفحه کلید استفاده می کنید. در مورد یک عمل پیمایش جانبی، مواردی وجود دارد که فقط از چپ و راست استفاده می شود، اما در اینجا ما فرض می کنیم که شما از چهار جهت با توجه به پریدن با کلید بالا و خم شدن با کلید پایین استفاده می کنید.

هنگامی که حرکت را انتخاب می کنید، یک انتخاب نوع عمل در سمت راست وجود دارد، بنابراین این را به "Value" تنظیم کنید.

نوع کنترل را در زیر خواهید دید، بنابراین Vector2 را انتخاب کنید. این به این دلیل است که بالا و پایین به Y اختصاص داده می شود و چپ و راست به X اختصاص داده می شود.

سپس کلیدی را که می خواهید به این رویداد اختصاص دهید انتخاب کنید. No Binding را در وسط انتخاب کنید و مسیر را در سمت راست انتخاب کنید. در اینجا ما LeftStick GamePad را انتخاب می کنیم.

این LeftStick GamePad را به حرکت متصل می کند.

برای اتصال کنترل کننده های دیگر نیز، "Add Binding" را از دکمه + به سمت راست Move انتخاب کنید.

اکنون که No Binding اضافه شده است، ما یک Dpad را برای GamePad اختصاص می دهیم.

به این ترتیب، شما می توانید نوع کنترل کننده ای را که می خواهید پشتیبانی کنید، و همچنین کلیدها و چوب ها را اضافه کنید. همچنین ممکن است ان را به طور خاص برای یک کنسول بازی خاص تنظیم کنید.

Sticks و Dpads دکمه هایی هستند که بالا، پایین، چپ و راست را فرض می کنند، بنابراین می توان انها را با این اضافه کرد، اما در مورد صفحه کلید، همه انها کلید های تک هستند، بنابراین هیچ تعریفی برای بالا، پایین، چپ و راست وجود ندارد. برای تنظیم صفحه کلید بالا، پایین، چپ یا راست، Add Up Down Left Right Composite را از دکمه + انتخاب کنید.

سپس یک بردار دو بعدی اضافه خواهد شد و شما می توانید ان را به هر بالا به سمت چپ راست اختصاص دهید، همانطور که در شکل زیر نشان داده شده است.

به عنوان مثال، اگر از Up استفاده می کنید، "Up Arrow" را روی صفحه کلید خود تنظیم کنید. به هر حال، اگر شما برای پیدا کردن یک کلید مشکل دارید، می توانید به راحتی ان را با فشار دادن کلید هدف در حالی که کلیک بر روی دکمه "گوش دادن" انتخاب کنید.

در حال حاضر به بالا Arrow تنظیم شده است.

به طور مشابه، پایین، چپ و راست را تنظیم کنید و کار شما تمام است.

البته، نه تنها کلیدهای مکان نما بلکه WASD را می توان تنظیم کرد.

بعد، پیکربندی حمله. حمله اسان است به اختصاص به دلیل ان است که یک دکمه تک. ابتدا Attack را انتخاب کنید و مطمئن شوید که Action Type یک دکمه است.

سپس No Binding را انتخاب کنید و دکمه ای را که می خواهید از Path اختصاص دهید انتخاب کنید.

اگر می خواهید بیشتر اضافه کنید، "Add Binding" را از دکمه + انتخاب کنید.

اضافه کردن به عنوان بسیاری که شما نیاز دارید. از انجا که به عنوان یک دکمه درمان می شود، صفحه کلید را می توان به همان شیوه ای که یک کنترل کننده بازی تنظیم می شود، تنظیم کرد.

هنگامی که تمام تنظیمات کامل شد، برای ذخیره روی "ذخیره دارایی" کلیک کنید. شما می توانید این پنجره را ببندید.

در نهایت، با فایل inputactions پروژه (در این مورد، فایل InputActionSample که قبلا ایجاد کرده اید)، "Generate C# Class" را در بازرس بررسی کنید. پارامتر اضافه خواهد شد، اما با کلیک بر روی دکمه "درخواست" به عنوان ان است.

این کار یک فایل اسکریپت با همان نام ایجاد خواهد کرد. این شامل کلاس هایی است که برای استفاده از نقشه های عمل از برنامه ها مفید هستند.

نحوه دریافت اطلاعات ورودی

راه های مختلفی برای دریافت ورودی بر اساس یک نقشه عمل وجود دارد. این نکته سه الگو را توضیح می دهد، اما بهتر است هنگام ساخت یک بازی بر روی یکی از انها تمرکز کنید. اگر از انها به طور جداگانه استفاده کنید، مدیریت ان دشوار خواهد بود.

همچنین، اگر از چندین روش دریافت ورودی در یک صحنه استفاده کنید، پردازش ممکن است در داخل تداخل داشته باشد و به درستی کار نکند.

دریافت اطلاعات ورودی در ارسال پیام

روش اول در اینجا نحوه دریافت اطلاعات ورودی در "ارسال پیام" است.

این بار، من می خواهم اطلاعات وارد شده را در متن نمایش دهم، بنابراین یک شیء متنی قرار می دهم.

همچنین، از انجا که این نکته سعی خواهد کرد اطلاعات ورودی چندگانه را دریافت کند، ما یک شی خالی برای تنظیم جزء به طور جداگانه ایجاد خواهیم کرد. این نام می تواند هر چیزی باشد.

بعد، یک جزء ورودی بازیکن را به شیء خالی اضافه کنید. ورودی بازیکن یک جزء مهم برای اتصال نقشه های اکشن و اسکریپت ها است.

در "اضافه کردن کامپوننت"، "ورودی بازیکن" در دسته "ورودی" وجود دارد، بنابراین ان را اضافه کنید.

هنگامی که جزء ورودی بازیکن اضافه شد، نقشه عملی را که در "Actions" ایجاد کرده اید تنظیم کنید. ان را از پروژه رها کنید یا ان را از ایکون + به سمت راست انتخاب کنید.

بررسی کنید که نقشه پیش فرض همان است که شما در نقشه عمل ایجاد کرده اید.

بررسی کنید که رفتار "ارسال پیام" است.

بعد، یک اسکریپت ایجاد کنید. نام فایل می تواند هر چیزی باشد، اما در اینجا 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}";
  }
}
  • شیء دارای یک ورودی بازیکن متصل است که ارسال پیام را تنظیم می کند
  • به ارث بردن از MonoBehaviour

اگر شرایط براورده شود، اگر روشی به نام "OnxxXXXXXX" تعریف کنید، روش هدف خواهد شد به نام زمانی که عملیات عمل مشخص انجام شده است. "XXXXXXXX" نام اقدامات ایجاد شده در نقشه عمل است. در اینجا، ما اقدامات "Move" و "Attack" را ایجاد کرده ایم، بنابراین نام روش به ترتیب "OnMove" و "OnAttack" است.

OnMove شما می توانید مبلغ وارد شده را از استدلال InputValue دریافت کنید. از انجا که نوع کنترل به "بردار 2" تنظیم شده است، مقدار InputValue.Get<Vector2> ورودی در دریافت خواهد شد.

OnAttackInputValue.isPressed شما می توانید دریافت کنید که ایا شما نیز فشار می اورید.

پس از ذخیره اسکریپت، ان را به یک شی که دارای جزء ورودی بازیکن است، متصل کنید. همچنین شیء متن را برای نمایش تنظیم کنید.

بازی را اجرا کنید و یک نگاه کنید. این بار، من تعریف گیم پد و صفحه کلید را شامل می شود، بنابراین باید بدون توجه به اینکه کدام یک از شما کار می کنید، کار کند.

همانطور که می بینید زمانی که ان را حرکت می دهید، می توانید ببینید که روش تنها زمانی نامیده می شود که تغییر در ارزش نسبت به حالت قبلی وجود داشته باشد. به عنوان مثال، در حالی که حرکت چوب به سمت چپ، ان را یکپارچه نامیده می شود، اما نه به سمت چپ (- OnMove 1.0). OnMove دکمه حمله نیز تنها در لحظه ای که فشار داده می شود پاسخ می دهد و اگر فشار داده شود و نگه داشته شود، روش نامیده نمی شود.

بنابراین، من فکر می کنم که استفاده ایده ال این است که انجام پردازش بازی زمانی که OnxxXXXXXX نامیده می شود، اما برای حفظ محتویات ورودی و استفاده از این مقادیر در پردازش به روز رسانی بازی.

به هر حال، در وضعیت فعلی، زمانی که دکمه ازاد می شود، نامیده نمی شود، بنابراین نمی توان تعیین کرد که دکمه چه زمانی OnAttack منتشر می شود. برای پاسخ به این، عمل حمله را انتخاب کنید که دکمه را در تنظیمات نقشه عمل تعریف می کند و "Press" را از "تعاملات" اضافه کنید. پس از ان، رفتار ماشه مطبوعات اضافه شده را به "مطبوعات و انتشار" تنظیم کنید و ان را ذخیره کنید.

هنگامی که اجرا می شود، می توانید ببینید که حتی OnAttack زمانی که دکمه ازاد می شود، نامیده می شود. isPressed false از انجا که می شود، همچنین می توان تعیین کرد که ایا زمان انتشار است.

به هر حال، لطفا این تعامل را حذف کنید زیرا در اینده استفاده نخواهد شد.

دریافت ورودی با Invoke Unity Events

راه دوم برای دریافت ورودی Invoke Unity Events است، بنابراین بیایید این را امتحان کنیم. همانطور که در بالا ذکر شد، استفاده از چندین روش ورودی می تواند باعث پردازش متناقض شود، بنابراین اگر پردازش های دیگر فعال شود، ان را غیرفعال کنید.

ابتدا شیء متن را قرار دهید تا اطلاعات ورودی نمایش داده شود.

Invoke Unity Events یک شیء خالی ایجاد می کند که عملیات مرتبط را انجام می دهد.

ورودی > Player را به شیء خالی اضافه کنید.

فایل نقشه عمل ایجاد شده برای Actions (در این مورد، 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 متدی که هنگام تعامل کاربر با ان نامیده می شود، مانند ارسال پیام است. در Invoke Unity Events، می توانید نام این روش را همانطور که دوست دارید تنظیم کنید.

هنگامی که هر یک نامیده می شود، ان را به عنوان یک InputAction.CallbackContext استدلال منتقل می شود، بنابراین شما می توانید وضعیت ورودی را از انجا دریافت کنید. اگر یک "مقدار" را در عمل تنظیم کنید، می توانید ان را در روش دریافت کنید و اگر یک "دکمه" تنظیم ReadValueAsButton کنیدReadValue، می توانید ان را در روش دریافت کنید.

پس از ذخیره اسکریپت، ورودی Player را به شیئی که تنظیم می کنید متصل کنید و شیء متن نمایش را تنظیم کنید.

بعد، "Event" و "Action Map Name (SideScrollActionMap)" را در ورودی Player گسترش دهید و باید اقدامات "Move" و "Attack" را که ایجاد کرده اید ببینید.

ابتدا روی دکمه + در Move کلیک کنید تا ان را اضافه کنید.

شیء در گوشه پایین سمت چپ شیء خودتان است و تابع بر روی روشی که ایجاد کرده اید تنظیم شده OnMove است.

رویداد حمله را نیز پیکربندی کنید.

بازی را اجرا کنید تا ببینید چگونه کار می کند.

اساسا، ان را تنها زمانی که همان مقدار به عنوان ارسال پیام تغییر می کند، اما به دلایلی روش ممکن است دو بار در همان زمان نامیده می شود. من علت را نمی دانم، اما فکر می کنم احتمالا به این دلیل است که فرایند شروع و فرایند مداوم همزمان در حال اجرا است. با این حال، من فکر می کنم که هیچ مشکلی وجود ندارد اگر شما فقط مقدار وارد شده را مانند مورد ارسال پیام ها نگه دارید و پردازش بازی واقعی را به طور جداگانه در فرایند به روز رسانی انجام دهید.

استفاده از یک دستنوشتۀ خودکار تولیدشده برای دریافت اطلاعات ورودی

بخش سوم توضیح می دهد که چگونه برای به دست اوردن اطلاعات ورودی با استفاده از یک اسکریپت تولید شده از یک فایل نقشه عمل.

از انجا که احتمال درگیری با سایر فرایندهای خرید وجود دارد، لطفا سایر فرایندهای خرید را غیرفعال کنید.

یک شیء متنی را برای نمایش اطلاعات ورودی قرار دهید.

همچنین، یک شیء خالی برای بازیابی اطلاعات ورودی ایجاد کنید. این مقاله از یک اسکریپت خودکار تولید شده استفاده می کند، بنابراین نیازی به اضافه کردن ورودی Player ندارید.

اسکریپت به طور خودکار از نقشه عمل تولید می شود فقط یک کتابخانه است، بنابراین یک اسکریپت کنترل جداگانه ایجاد کنید. این نام خودسرانه است، اما در این مورد 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 عملیات Move (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 ظاهر می شود.