Featured image of post Input System (part 1 80%)

Input System (part 1 80%)

Cùng tìm hiểu về hệ thống Input mới của Unity

Giới thiệu

Chà Unity đã phát triển hệ thống Input mới để thay thế cho cái cũ dưới tên gọi Input System và được cài thông qua package manager. hệ thống cũ vẫn được giữ nguyên để giữ nguyên khả năng tương thích ngược cũng như nhiều người vẫn quen dùng cách cũ và họ ngại sử cách mới.

Bài viết này nhằm tìm hiểu cách sử dụng cơ bản nhất Input System package.

Môi trường

Mình thực hiện thử nghiệm trên Unity phiên bản 2022.3.2f1 và Input System phiên bản 1.6.1

Nội dung

Input System Package là gì?

Nó là một hệ thống đầu vào mới để thay thế cho cách tiếp cận cũ nếu bạn chưa biết thì hệ thống cũ tên là Input Manager

Nó có thể tích hợp và xử lý nhiều loại thiết bị đầu vào khác nhau như keyboard, mouse, gamepad, joystick, touch screen … vân vân.

Document chính thức bạn có thể tìm thấy ở đây

Nó giải quyết các vấn đề của Input Manager như:

  • gán các nút hoặc trục của gamepad
  • phát hiện long press hoặc double click, vân vân
  • cấu hình phím
  • chuyển đổi giữa các loại dữ liệu đầu vào khác nhau như chuyển giữa màn hình cảm ứng sang gamepad hoặc ngược lại mặc dù hệ thống cũ vẫn có thể làm được ở một mức độ nào đấy.

Ngoài ra nó cũng bổ sung thêm các chức năng hỗ trợ mà Input Manager không có.

Cài đặt

Cài đặt Input System khá đơn giản, bạn chỉ cần bật Package Manager và chọn Input System và nhấn Install để cài phiên bản mới nhất

Ví dụ xử lý đầu vào là keyboard

Ví dụ dưới đây là cách dùng để xác định xem một phím trên bàn phím có được nhấn hay không.

Tạo script KeyboardExample và copy đoạn code bên trên sau đấy đính kèm vào một GameObject trong scene và chạy thử.

Ở đây các API sử dụng là của namespace UnityEngine.InputSystem

1
 using UnityEngine.InputSystem;

Thông tin của keyboard nhận được thông qua câu lệnh

1
 var current = Keyboard.current;

Và trong trường hợp đầu vào của bạn không phải keyboard thì current sẽ có giá trị null vì vậy chúng ta cần kiểm tra null cho nó

1
2
3
4
 if (current == null)
 {
     return;
 }

Thông tin của phím A trên bàn phím lấy được từ câu lệnh

1
 var aKey = current.aKey;

Ngoài ra bạn cũng có thể lấy thông tin phím A theo cách sau

1
 var aKey = current[Key.A];

Biến aKey có kiểu dữ liệu là KeyControl chứa dữ liệu về trạng thái của phím

Bạn cũng có thể tìm thấy cách truy cập vào các phím khác ở đây

  • wasPressedThisFrame cho biết thời điểm phím được nhấn
  • wasReleasedThisFrame cho biết thời điểm phím được thả ra
  • isPressed cho biết liệu phím có đang được nhấn hay không?

Các thuộc tính này tương đương với các thuộc tính trong hệ thống cũ Input Manager theo bảng dưới đây

Input System Input Manager
wasPressedThisFrame Input.GetKeyDown()
wasReleasedThisFrame Input.GetKeyUp()
isPressed Input.GetKey()

Ví dụ xử lý đầu vào là mouse

Ví dụ dưới đây xác định các thao tác khi nhấn chuột trái

Thông tin của mouse nhận được thông qua câu lệnh sau

1
 var current = Mouse.current;

Và trong trường hợp đầu vào của bạn không phải mouse thì current sẽ có giá trị null vì vậy chúng ta cần kiểm tra null cho nó

1
 if (current == null) return;

Lấy ra vị trí hiện tại của chuột, giá trị trả về là vector2

1
 var mousePosition = current.position.ReadValue();

Thông tin của chuột trái nhận được qua thuộc tính leftButton

1
 var leftMouse = current.leftButton;

Nếu chưa nhấn chuột trái thì current.leftButton sẽ trả về null ta cần kiểm tra điều này.

1
if (leftMouse == null) return;

Phát hiện nhấn chuột, hay thả ra cũng tương tự ta có

1
2
3
 if (leftMouse.wasPressedThisFrame) Debug.Log("OnMouseDown :" + mousePosition);
 if (leftMouse.wasReleasedThisFrame) Debug.Log("OnMouseUp :" + mousePosition);
 if (leftMouse.isPressed) Debug.Log("MousePressed :" + mousePosition);

Bạn có truy cập những nút khác của chuột, có thể tìm thấy ở đây

Trừu tượng hóa việc phát hiện đầu vào với Action

Ở hai ví dụ trước chúng ta đã cùng tìm hiểu về việc lấy giá trị đầu vào của mouse cũng như keyboard bằng các đoạn code cụ thể.

Tuy nhiên, phương pháp này có nhược điểm là hard code việc triển khai phát hiện đầu vào của thiết bị ở phía logic trò chơi, làm giảm tính linh hoạt và khả năng mở rộng.

Điều này có thể được giải quyết bằng cách trừu tượng hóa nó bằng khái niệm Action. Action là đơn vị của hoạt động. Ví dụ các hoạt động như “moving”, “jumping” của nhân vật có thể xử lý dưới dạng Action

Điều này giúp phía logic trò chơi có thể viết code mà không cần quan tâm đầu vào đến từ controller nào. Nó cũng có ưu điểm là hỗ trợ các controller mới dễ dàng hơn.

Ánh xạ giữa controller và Action được gọi là binding

Như đã trình bày ở trên, Jump Action mà nút Space trên keyboard và button X trên gamepad được ánh xạ bởi 2 bindings

Bạn có thể tìm hiểu thêm khái niệm đấy ở đây

Nhận thông tin đầu vào thông qua Action

Các Action được xử lý như instance của class InputAction

Để khai báo một InputAction bạn có thể làm như sau:

1
 [SerializeField] private InputAction inputAction;

Lúc này bạn có thể chỉnh sửa input action từ bên ngoài inspector

Hãy xem ví dụ sau để hình dung rõ hơn

Đính kèm đoạn code trên vào gameObject trong scene và tùy chỉnh inputAction

Tiếp theo nhấn vào dấu + và thêm binding ta được

Nhấn đúp vào mục no binding để hiển thị menu và chọn button space trên keyboard cho thuộc tính Path

Nút listen được sử dụng để gắn bằng phím nhập thực tế từ input của bạn nếu không bạn có thể chọn từ danh sách hiển thị và tìm theo tên của chúng

Khi chạy chúng ta sẽ thu được kết quả như sau

Giá trị đầu ra là 0 hoặc 1 vì nó được nhận dưới dạng giá trị đầu vào của loại float (1 axis). Ở đây chỉ có 2 giá trị bởi vì nó chỉ có 2 trạng thái là nhấn hoặc không nhấn mà thôi

Nếu bạn binding bằng analog hoặc joystick giá trị nhận được sẽ thay đổi trong khoảng 0 đến 1

Nhận Input Action thông qua callback

Một tính năng quan trọng khác cuủa Action đó là nó cung cấp cách truyền giá trị đầu vào dưới dạng callback khi gặp một số input nhất định.

Ví dụ dưới đây sẽ kích hoạt event vào các thời điểm sau :

  • thời điểm nhấn nút
  • khi có giá trị đầu vào liên tục chẳng hạn như vị trí chuột
  • khi nút được giữ trong một khoảng thời gian liên tục
  • khi double click

Đối với hệ thống cũ InputManager chúng ta cần xử lý logic bằng cách phát hiện thời điểm nhấn nút bằng Input.GetMouseButtonDown() sau đấy sử dụng Update hoặc coroutine để phát hiện longClick hoặc doubleClick.

Cài đặt y hệt ví dụ trước đó nhưng chúng ta sẽ tùy chỉnh ActionType

  • Value : cài đặt để nhận callback theo giá trị
  • Button : cài đặt để nhận callback ngay lập tức khi button được nhấn
  • Pass Through : …

Xem document cụ thể hơn ở đây

Trong trường hợp này chúng sẽ đổi ActionType thành Button

Quản lý nhiều Action giống như asset

Các ví dụ trước đấy đều là về xử lý đơn lẻ một Action trong một script đơn giản

Trong thực tế bạn sẽ xử lý một số lượng lớn Action. Ngoài Action của người chơi, bạn cũng có thể quản lý các loại Action hoàn toàn khác, chẳng hạn như Action trên giao diện người dùng.

Thông tin đặt cho nhiều Action như thế này có thể được lưu dưới dạng file asset có tên là Input Action Asset

Các loại Action như Player Action và UI Action có thể nhóm bằng các đơn vị được gọi là Map và chuyển đổi dễ dàng giữa chúng.

Input Action Asset cũng có thể quản lý thông tin của group theo loại của controller (keyboard, mouse, gamepad …) được gọi là Control Scheme.

… (Còn tiếp)

yenmoc
Lượt nghé thăm