U
tab 03Camera & Điều khiển6 bài — chạm để mở
04 / 06 · 11 phút
Camera & Điều khiển

Input System mới

dự án của bạn tới lúc này

Assets/

Scripts/

PlayerMovement.csCharacterSwitcher.csSkillCaster.csInput.GetAxis / GetKey→InputRouter.cs

Settings/

PlayerControls.inputactions

thiết lập dự án

Input System package

đã có sẵnbài này thêmbài này thay thế

Ba script bạn đã viết vẫn gọi thẳng Input: PlayerMovement đọc GetAxisRaw, CharacterSwitcher đọc phím số, SkillCaster đọc Q, E, R. Cả ba đều dính chết vào bàn phím — và đó là vấn đề, vì tab 05 sẽ đưa cái này lên điện thoại.

Input System cho bạn định nghĩa hành động một lần rồi gán phím, tay cầm và cảm ứng vào đó. Học xong bài này, không script gameplay nào của bạn còn biết người chơi đang cầm thiết bị gì.

sơ đồ động

Thiết bị bên trái, một file action ở giữa, code gameplay của bạn bên phải.

Cài và chuyển sang dùng

  1. 1

    Package Manager → Input System → Install. Unity hỏi khởi động lại; chọn có.

  2. 2

    Edit▸Project Settings▸Player▸Active Input Handling → chọn Both trong lúc chuyển đổi.

  3. 3

    Project: Create▸Input Actions, đặt tên PlayerControls, bấm đúp để mở trình soạn.

  4. 4

    Tick Generate C# Class rồi bấm Apply — Unity tự sinh ra class bọc sẵn.

Dựng bản đồ hành động

  1. 1

    Thêm một Action Map tên Gameplay.

  2. 2

    Action Move → Action Type Value → Control Type Vector2. Thêm binding kiểu 2D Vector Composite: W/A/S/D. Thêm binding nữa: cần trái tay cầm.

  3. 3

    Action Look → Value → Vector2 → gán Mouse Delta và cần phải tay cầm.

  4. 4

    Action Jump và Attack → Action Type Button → gán Space / nút South và chuột trái / nút West.

  5. 5

    Action Skill1 / Skill2 / Skill3 → Button → gán Q, E, R. Chúng thay cho các phím mà SkillCaster đang tự đọc.

  6. 6

    Action SwapCharacter → Value / Axis → gán phím 1, 2, 3. Chúng thay cho phần CharacterSwitcher đang tự đọc.

Đọc trong code

InputRouter.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class InputRouter : MonoBehaviour
{
    //do class sinh tự động điền vào
    private PlayerControls controls;

    public Vector2 Move { get; private set; }
    public Vector2 Look { get; private set; }
    public bool JumpPressed { get; private set; }

    void Awake()
    {
        controls = new PlayerControls();

        controls.Gameplay.Move.performed += ctx => Move = ctx.ReadValue<Vector2>();
        controls.Gameplay.Move.canceled  += ctx => Move = Vector2.zero;   // đừng bao giờ quên dòng này

        controls.Gameplay.Look.performed += ctx => Look = ctx.ReadValue<Vector2>();
        controls.Gameplay.Look.canceled  += ctx => Look = Vector2.zero;

        controls.Gameplay.Jump.performed += ctx => JumpPressed = true;
        controls.Gameplay.Attack.performed += ctx => GetComponent<SkillCaster>().TryCast(0);
    }

    void OnEnable()  => controls.Enable();    // quên là không nhận phím
    void OnDisable() => controls.Disable();

    void LateUpdate() => JumpPressed = false; // cờ chỉ đúng trong 1 khung hình
}
  • performed chạy khi bắt đầu hoặc thay đổi; canceled chạy khi thả ra. Quên canceled là nhân vật đi mãi không dừng.

  • Move là Vector2 (x, y). Trong 3D bạn ánh xạ thành (x, 0, y) — trục y của cần gạt thành trục Z của thế giới.

  • Một action map thứ hai tên UI có thể bật lên khi Gameplay bị tắt — đó là cách menu tạm dừng chặn nhân vật di chuyển.

Loại bỏ ba chỗ đọc phím cũ

Đây là phần dọn dẹp làm cho cả tab này đáng công. Xoá mọi Input.GetAxis, Input.GetKey, Input.GetMouseButton trong dự án và cho chúng đi qua InputRouter.

ba chỗ cần sửa
// 1 — PlayerMovement.cs
- float h = Input.GetAxisRaw("Horizontal");
- float v = Input.GetAxisRaw("Vertical");
- Vector3 input = new Vector3(h, 0f, v).normalized;
+ Vector3 input = new Vector3(router.Move.x, 0f, router.Move.y).normalized;

// 2 — CharacterSwitcher.cs
- for (int i = 0; i < characters.Count && i < 9; i++)
-     if (Input.GetKeyDown(KeyCode.Alpha1 + i)) Select(i);
+ // in InputRouter.Awake:
+ controls.Gameplay.SwapCharacter.performed += c => switcher.Select((int)c.ReadValue<float>() - 1);

// 3 — SkillCaster.cs
- for (int i = 0; i < skills.Count && i < keys.Length; i++)
-     if (Input.GetKeyDown(keys[i])) TryCast(i);
+ // in InputRouter.Awake:
+ controls.Gameplay.Skill1.performed += _ => caster.TryCast(0);
+ controls.Gameplay.Skill2.performed += _ => caster.TryCast(1);
+ controls.Gameplay.Skill3.performed += _ => caster.TryCast(2);

Dùng trong script di chuyển

C# script
[SerializeField] private InputRouter input;

void Update()
{
    Vector3 dir = new Vector3(input.Move.x, 0f, input.Move.y);
    //phần còn lại y hệt script cũ
}

✓ PlayerInput component

Kéo thả, ít code

Chế độ Send Messages / Unity Events. Dựng nhanh nhất, hợp làm nguyên mẫu.

✓ Generated C# class

Class tự sinh

Rõ ràng, đổi tên an toàn, không phụ thuộc tên hàm dạng chuỗi. Hợp dự án thật.