输入操作
本课属于 Coddy Unity 学习旅程的“打造真正的游戏”单元。第 47 课,共 60 课。
逐个检测按键会让脚本依赖键盘。动作代表玩家要做的事,而项目会列出触发该动作的按键、摇杆和按钮。新的 Unity 6 项目自带一组动作(InputSystem_Actions 资源,设为整个项目共用的动作),其中 Player 映射包含 Move(WASD、方向键和游戏手柄的左摇杆)、Look(鼠标或右摇杆)、Attack(鼠标左键和 Enter)、Interact(按住 E)、Crouch(C)、Jump(空格键和游戏手柄的南键)、Previous 和 Next(1 和 2),以及 Sprint(左 Shift)。这些动作从一开始就已启用,可以通过名称用 InputSystem.actions.FindAction("Jump") 获取。这个横向视角的抓娃娃机在 x 轴和 y 轴上移动,并在按下 Jump 时抓取物品:
using UnityEngine;
using UnityEngine.InputSystem;
public class ClawCrane : MonoBehaviour
{
public float speed = 3f;
private InputAction moveAction;
private InputAction jumpAction;
void Start()
{
moveAction = InputSystem.actions.FindAction("Move");
jumpAction = InputSystem.actions.FindAction("Jump");
}
void Update()
{
Vector2 input = moveAction.ReadValue<Vector2>();
transform.position += new Vector3(input.x, input.y, 0f) * speed * Time.deltaTime;
if (jumpAction.WasPressedThisFrame())
Debug.Log("Grab!");
}
}动作只在 Start 中查找一次,并保存在 InputAction 字段中。Move 会提供一个 Vector2:x 表示左右方向,y 表示按键控制的上下方向,而且结果会经过归一化,因此同时按下 W 和 D 得到的是 (0.71, 0.71),而不是 (1, 1)。这是横向视角,所以抓娃娃机会用 y 表示高度;俯视角游戏则会用它表示 z。按钮动作的响应方式和按键一样:WasPressedThisFrame()、WasReleasedThisFrame() 和 IsPressed()。两种错误会导致异常:名称拼错时,FindAction 会返回 null(首次读取时会出现 NullReferenceException);对 Move 调用 ReadValue<Vector3>() 时,只要按住一个按键就会抛出 InvalidOperationException,因为 Move 使用的是 Vector2。
挑战
中等使用项目中的操作来移动测量员并插旗。
- 在
Start()中,使用InputSystem.actions.FindAction("Move")、"Jump"和"Attack"设置moveAction、jumpAction和attackAction。 - 在
Update()中,通过moveAction.ReadValue<Vector2>()乘以speed来移动,y 分量沿 z 轴移动。 - 当
jumpAction.WasPressedThisFrame()时调用Plant(),按下 Attack 时调用PullUp()。
点击 开始,插下三面旗子,然后点击拔起一面。接着点击 检查。
亲手试试
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class Surveyor : MonoBehaviour
{
public float speed = 4f;
public int flags = 3;
public GameObject flagPrefab;
private InputAction moveAction;
private InputAction jumpAction;
private InputAction attackAction;
private List<GameObject> planted = new List<GameObject>();
void Start()
{
// 找到 Move、Jump 和 Attack 操作
}
void Update()
{
// 用 Move 行走,按下 Jump 时调用 Plant(),按下 Attack 时调用 PullUp()
}
void Plant()
{
if (flags == 0) return;
Vector3 spot = new Vector3(transform.position.x, 0.75f, transform.position.z);
planted.Add(Instantiate(flagPrefab, spot, Quaternion.identity));
flags--;
Debug.Log("Flags left: " + flags);
}
void PullUp()
{
if (planted.Count == 0) return;
GameObject last = planted[planted.Count - 1];
planted.RemoveAt(planted.Count - 1);
Destroy(last);
flags++;
Debug.Log("Flags left: " + flags);
}
}
打造真正的游戏中的所有课
自己练习: Unity 在线编辑器