Sử dụng bản đồ hành động để gán các nút cho hành vi trò chơi

Trang Cập Nhật :
Ngày tạo trang :

Môi trường xác minh

Windows
  • cửa sổ 11
Biên tập viên Unity
  • 2020.3.25f1
Gói hệ thống đầu vào
  • 1.2.0

Điều kiện tiên quyết cho mẹo này

Các cài đặt sau đây đã được thực hiện trước làm tiền đề cho mô tả về mẹo này.

Giới thiệu về Bản đồ hành động

Các chương trình nhập liệu của người dùng trên bàn phím, chuột và gamepad về cơ bản tuyên bố rằng một hành động nhất định đã được thực hiện khi nhấn nút. Ví dụ: trong bản đồ hành động, bạn có thể xác định hành động "nhảy" và gán các nút điều khiển và phím bàn phím cho nó. Do đó, chương trình chỉ cần mô tả quá trình khi một hành động cụ thể được thực hiện. Ngay cả khi bạn gán một nút trên bộ điều khiển khác làm suy nghĩ sau, bạn có thể áp dụng nó mà không cần thay đổi chương trình vận hành.

Tạo bản đồ hành động

Ở đây, tôi muốn tạo một action map và hiển thị thông tin đầu vào của người dùng trong văn bản. Có một số cách để nhận thông tin đầu vào của người dùng bằng Bản đồ hành động.

Bấm chuột phải vào bất kỳ thư mục nào trong dự án để tạo Hành động nhập. Vị trí của thư mục sẽ được tạo là tùy ý, nhưng vui lòng quản lý nó theo dự án của bạn. Tên tệp cũng tùy ý, nhưng đây InputActionSample là .

Khi bạn nhấp đúp vào tệp đã tạo, cửa sổ sau sẽ được hiển thị.

Đầu tiên, nhấp vào nút + trong Bản đồ hành động để tạo bản đồ hành động. Là một đơn vị sáng tạo, nếu nội dung của hoạt động thay đổi tùy theo cảnh, nó sẽ được xác định trong đơn vị đó. Ví dụ: trong trường hợp trò chơi hành động cuộn bên, nội dung của thao tác thay đổi trong hành động và trong menu, vì vậy bạn sẽ tạo một bản đồ hành động cho từng trò chơi.

Ở đây, làm ví dụ, chúng tôi định nghĩa một hành động cuộn bên và đặt tên cho nó là "SideScrollActionMap".

Tiếp theo, tạo Actions. Vì nó là một mẫu, tôi sẽ không tạo ra nhiều trong số chúng, nhưng ở đây chúng tôi sẽ tạo các hành động "Di chuyển" để di chuyển và "Tấn công" để tấn công. Vì một tên đã được tạo, vui lòng thay đổi tên hoặc tạo tên mới, nhấp vào nút + ở góc trên bên phải và nhập nó.

Đầu tiên, định cấu hình cấu hình Di chuyển. Bộ điều khiển giả định rằng bạn sử dụng thanh, D-pad và phím con trỏ bàn phím. Trong trường hợp hành động cuộn bên, có những trường hợp chỉ sử dụng trái và phải, nhưng ở đây chúng tôi giả định rằng bạn sử dụng bốn hướng xem xét nhảy bằng phím trên và cúi xuống bằng phím xuống.

Khi bạn chọn Di chuyển, có một lựa chọn Loại hành động ở bên phải, vì vậy hãy đặt tùy chọn này thành "Giá trị".

Bạn sẽ thấy Control Type bên dưới, vì vậy hãy chọn Vector2. Điều này là do trên cùng và dưới cùng được gán cho Y, và bên trái và bên phải được gán cho X.

Sau đó, chọn khóa bạn muốn gán cho sự kiện này. Chọn Không ràng buộc ở giữa và chọn Đường dẫn ở bên phải. Ở đây chúng tôi chọn GamePad LeftStick.

Điều này liên kết LeftStick của GamePad với Move.

Để liên kết các bộ điều khiển khác, hãy chọn "Thêm ràng buộc" từ nút + ở bên phải Di chuyển.

Bây giờ Không ràng buộc được thêm vào, chúng tôi chỉ định một Dpad cho GamePad.

Bằng cách này, bạn có thể thêm loại bộ điều khiển bạn muốn hỗ trợ, cũng như các phím và gậy. Cũng có thể đặt nó cụ thể cho một bảng điều khiển trò chơi cụ thể.

Gậy và Dpad là các nút giả định lên, xuống, trái và phải, vì vậy chúng có thể được thêm vào với điều này, nhưng trong trường hợp bàn phím, chúng đều là các phím đơn, vì vậy không có định nghĩa cho lên, xuống, trái và phải. Để thiết lập bàn phím lên, xuống, trái hoặc phải, hãy chọn Add Up Down Left Right Composite từ nút +.

Một Vector 2D sau đó sẽ được thêm vào và bạn có thể gán nó cho mỗi Up Down Left Right, như thể hiện trong hình bên dưới.

Ví dụ: nếu bạn sử dụng Lên, hãy đặt "Mũi tên lên" trên bàn phím. Nhân tiện, nếu bạn gặp rắc rối khi tìm khóa, bạn có thể dễ dàng chọn nó bằng cách nhấn phím mục tiêu trong khi nhấp vào nút "Nghe".

Up hiện được đặt thành Mũi tên lên.

Tương tự, đặt Xuống, Trái và Phải và bạn đã hoàn tất.

Tất nhiên, không chỉ các phím con trỏ mà cả WASD cũng có thể được đặt.

Tiếp theo, cấu hình Attack. Tấn công rất dễ gán vì nó là một nút duy nhất. Đầu tiên, chọn Attack và đảm bảo Action Type là một nút.

Sau đó chọn Không ràng buộc và chọn nút bạn muốn gán từ Đường dẫn.

Nếu bạn muốn thêm nhiều hơn, hãy chọn "Thêm ràng buộc" từ nút +.

Thêm bao nhiêu tùy thích. Vì nó được coi là một nút, bàn phím có thể được đặt giống như bộ điều khiển trò chơi.

Khi tất cả các cài đặt hoàn tất, hãy nhấp vào "Lưu tài sản" để lưu. Bạn có thể đóng cửa sổ này.

Cuối cùng, với tệp đầu vào của dự án (trong trường hợp này là tệp InputActionSample bạn đã tạo trước đó), hãy chọn "Tạo lớp C #" trong trình kiểm tra. Tham số sẽ được thêm vào, nhưng nhấp vào nút "Áp dụng" như hiện tại.

Thao tác này sẽ tạo ra một tệp tập lệnh có cùng tên. Nó chứa các lớp hữu ích cho việc sử dụng bản đồ hành động từ các chương trình.

Cách tiếp nhận thông tin đầu vào

Có một số cách để nhận thông tin đầu vào dựa trên bản đồ hành động. Mẹo này giải thích ba mẫu, nhưng tốt hơn là tập trung vào một trong số chúng khi thực sự tạo trò chơi. Nếu bạn sử dụng chúng một cách riêng biệt, sẽ rất rắc rối khi quản lý.

Ngoài ra, nếu bạn sử dụng nhiều phương thức nhận đầu vào trong một cảnh, quá trình xử lý có thể xung đột nội bộ và không hoạt động chính xác.

Nhận thông tin đầu vào trong Gửi tin nhắn

Phương pháp đầu tiên ở đây là cách nhận thông tin đầu vào trong "Gửi tin nhắn".

Lần này, tôi muốn hiển thị thông tin đã nhập trong văn bản, vì vậy tôi sẽ đặt một đối tượng văn bản.

Ngoài ra, vì mẹo này sẽ cố gắng lấy nhiều thông tin đầu vào, chúng tôi sẽ tạo một đối tượng trống để đặt thành phần riêng biệt. Tên có thể là bất cứ điều gì.

Tiếp theo, thêm một thành phần Player Input vào đối tượng trống. Đầu vào của người chơi là một thành phần quan trọng để kết nối bản đồ hành động và tập lệnh.

Trong "Thêm thành phần", có "Đầu vào của người chơi" trong danh mục "Đầu vào", vì vậy hãy thêm nó.

Khi thành phần Đầu vào của Trình phát được thêm vào, hãy đặt bản đồ hành động bạn đã tạo trong "Hành động". Thả nó khỏi dự án hoặc chọn nó từ biểu tượng + ở bên phải.

Xác minh rằng Bản đồ mặc định là bản đồ bạn đã tạo trong bản đồ hành động.

Xác minh rằng hành vi là "Gửi tin nhắn".

Tiếp theo, tạo một tập lệnh. Tên tệp có thể là bất cứ thứ gì, nhưng đây InputSendMessage là .

Kịch bản trông như thế này:

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}";
  }
}
  • Đối tượng có một Player Input đính kèm đặt Gửi tin nhắn
  • Kế thừa từ MonoBehavior

Nếu các điều kiện được đáp ứng, thì nếu bạn xác định một phương thức có tên là "OnXXXXXXXX", Phương thức đích sẽ được gọi khi thao tác hành động được chỉ định được thực hiện. "XXXXXXXX" là tên của Hành động được tạo trong bản đồ hành động. Ở đây, chúng ta đã tạo các hành động "Move" và "Attack", vì vậy tên phương thức lần lượt là "OnMove" và "OnAttack".

OnMove Bạn có thể nhận được số tiền được nhập từ đối số InputValue của . Vì Control Type được đặt thành "Vector 2", giá trị InputValue.Get<Vector2> đầu vào sẽ được nhận trong .

OnAttackInputValue.isPressed Bạn cũng có thể nhận được liệu bạn có đang nhấn vào hay không.

Sau khi bạn lưu tập lệnh, đính kèm nó vào một đối tượng có một thành phần Player Input. Đặt đối tượng văn bản để hiển thị là tốt.

Chạy trò chơi và xem. Lần này, tôi đã bao gồm định nghĩa về gamepad và bàn phím, vì vậy nó sẽ hoạt động cho dù bạn vận hành cái nào.

Như bạn có thể thấy khi bạn di chuyển nó, bạn có thể thấy rằng phương thức chỉ được gọi khi có sự thay đổi về giá trị so với trạng thái trước đó. Ví dụ, trong khi di chuyển cây gậy sang trái, nó được gọi là một đầu, nhưng không phải sang trái (- OnMove 1,0). OnMove Nút Attack cũng chỉ phản hồi ngay khi nó được nhấn và nếu nó được nhấn và giữ, phương thức sẽ không được gọi.

Do đó, tôi nghĩ rằng cách sử dụng lý tưởng không phải là thực hiện xử lý trò chơi khi OnXXXXXXXX được gọi, mà chỉ giữ lại nội dung đầu vào và sử dụng các giá trị đó trong quá trình xử lý cập nhật của trò chơi.

Nhân tiện, ở trạng thái hiện tại, nó không được gọi khi nút được nhả ra, vì vậy không thể xác định khi nào OnAttack nút được nhả ra. Để phản hồi điều này, hãy chọn hành động Tấn công xác định nút trong cài đặt bản đồ hành động và thêm "Nhấn" từ "Tương tác". Sau đó, đặt Hành vi kích hoạt của báo chí đã thêm thành "Nhấn và phát hành" và lưu nó.

Khi được thực thi, bạn có thể thấy điều đó được gọi ngay cả OnAttack khi nút được nhả ra. isPressed false Kể từ khi nó trở thành , cũng có thể xác định xem đó có phải là thời điểm phát hành hay không.

Nhân tiện, vui lòng xóa tương tác này vì nó sẽ không được sử dụng trong tương lai.

Nhận thông tin đầu vào với Invoke Unity Events

Cách thứ hai để nhận đầu vào là Invoke Unity Events, vì vậy hãy thử điều này. Như đã đề cập ở trên, sử dụng nhiều phương thức đầu vào có thể gây ra quá trình xử lý xung đột, vì vậy nếu xử lý khác được bật, hãy tắt nó.

Đầu tiên, đặt đối tượng văn bản để thông tin đầu vào có thể được hiển thị.

Gọi Unity Events tạo một đối tượng trống thực hiện các thao tác liên quan.

Thêm Input > Player Input vào đối tượng trống.

Đặt tệp bản đồ hành động bạn đã tạo cho Hành động (trong trường hợp này là InputActionSample) và đặt Bản đồ hành động bạn đã tạo (trong trường hợp này là SideScrollActionMap) thành Bản đồ mặc định. Đặt hành vi để gọi sự kiện Unity.

Tạo tập lệnh. Tên là tùy ý, nhưng trong trường hợp InputInvokeUnityEvents này là .

Kịch bản trông như thế này:

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

Tên OnMoveOnAttack phương thức được gọi khi người dùng tương tác với nó là , như trong trường hợp Gửi tin nhắn. Trong Invoke Unity Events, bạn có thể đặt tên phương thức này theo ý muốn.

Khi mỗi được gọi, nó được truyền dưới dạng InputAction.CallbackContext đối số, vì vậy bạn có thể nhận được trạng thái đầu vào từ đó. Nếu bạn đặt "giá trị" trong hành động, bạn có thể nhận nó trong phương thức và nếu bạn đặt ReadValueAsButton "nút", bạn ReadValue có thể nhận nó trong phương thức.

Sau khi lưu tập lệnh, hãy đính kèm Đầu vào Player vào đối tượng bạn đang đặt và đặt đối tượng văn bản hiển thị.

Tiếp theo, mở rộng "Sự kiện" và "Tên bản đồ hành động (SideScrollActionMap)" trong Nhập trình phát và bạn sẽ thấy các hành động "Di chuyển" và "Tấn công" mà bạn đã tạo.

Đầu tiên, nhấp vào nút + trên Di chuyển để thêm nó.

Đối tượng ở góc dưới bên trái là đối tượng của riêng bạn, và Hàm được đặt thành phương thức bạn vừa tạo OnMove .

Định cấu hình cả sự kiện Tấn công.

Chạy trò chơi để xem nó hoạt động như thế nào.

Về cơ bản, nó chỉ được gọi khi cùng một giá trị với Gửi tin nhắn thay đổi, nhưng vì một số lý do, phương thức có thể được gọi hai lần cùng một lúc. Tôi không biết nguyên nhân, nhưng tôi nghĩ có lẽ là do quá trình bắt đầu và quá trình liên tục đang chạy cùng một lúc. Tuy nhiên, tôi nghĩ rằng sẽ không có vấn đề gì nếu bạn chỉ giữ giá trị đã nhập như trong trường hợp Gửi tin nhắn và thực hiện xử lý trò chơi thực tế riêng biệt trong quá trình Cập nhật.

Sử dụng tập lệnh được tạo tự động để nhận thông tin đầu vào

Phần thứ ba mô tả cách lấy thông tin đầu vào bằng cách sử dụng tập lệnh được tạo từ tệp bản đồ hành động.

Vì có khả năng xung đột với các quy trình mua lại khác, vui lòng vô hiệu hóa các quy trình mua lại khác.

Đặt một đối tượng văn bản để hiển thị thông tin đầu vào.

Ngoài ra, tạo một đối tượng trống để truy xuất thông tin đầu vào. Bài viết này sử dụng tập lệnh được tạo tự động, vì vậy bạn không cần thêm Nhập trình phát.

Tập lệnh được tạo tự động từ bản đồ hành động chỉ là một thư viện, vì vậy hãy tạo một tập lệnh điều khiển riêng biệt. Tên là tùy ý, nhưng trong trường hợp InputScript này là .

Kịch bản trông như thế này:

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

Xác định lớp InputActionSample được tạo tự động từ bản đồ hành động trong trường. Lớp này định nghĩa từng hành động được tập hợp trong bản đồ hành động và bạn có thể đặt các sự kiện được gọi khi các hành động đó được thực hiện.

Awake Trong phương thức, InputActionSample một thể hiện của được tạo và sự kiện được gọi tại thời điểm hành động được đặt. Khi OnMovebạn thực hiện các thao tác này, phương thức , OnAttack bây giờ được gọi.

Tuy nhiên, vì chúng ta chỉ đặt sự kiện ở đây, chúng ta OnEnable cần gọi phương thức khi Enable được gọi để kích hoạt bản đồ hành động.

Ngoài ra, vì hành vi đầu vào của người dùng được coi là một hoạt động toàn cầu, Để ngăn bản OnDisable đồ hành động làm thêm sau khi đối tượng này bị vô hiệu hóa, chúng tôi gọi phương thức trong Disable phương thức để vô hiệu hóa nó.

Sau khi lưu tập lệnh, hãy đính kèm nó vào đối tượng trống mà bạn đã tạo và đặt đối tượng văn bản để hiển thị.

Chạy trò chơi để xem nó hoạt động như thế nào.

Như bạn có thể thấy, phương thức không được gọi khi OnMove thao tác Di chuyển trở thành (0, 0). Tôi không chắc tại sao, nhưng có vẻ như sự kiện được thực hiện chỉ thực sự lấy một với tổ hợp phím được bật.

Nhân tiện, nếu bạn chưa đặt Tương tác trong bản đồ hành động cho Attack, nó sẽ không được gọi khi OnAttack bạn nhả nút.

Để canceled xử lý việc này, bạn cần thiết lập một sự kiện. Nếu bạn không muốn thực hiện xử lý đặc biệt tại (0, 0), bạn có thể gọi phương thức như nó là OnMove . Điều này cũng đúng với Attack.

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

Chạy và xác minh rằng Move:(0, 0) hoặc Attack:False xuất hiện.