Unity使用Input系统
在 Unity 中获取鼠标和键盘输入,核心依赖 旧版 Input Manager(简单直观)或 新版 Input System(功能强大)。以下是两种系统的具体实现方法,覆盖「键盘按键检测、轴向输入、鼠标位置/按键/滚轮、拖拽」等核心场景,直接复制代码即可使用。
一、旧版 Input Manager(推荐快速开发/简单项目)
无需额外安装,直接通过 Input 类静态 API 调用,适合原型开发或简单交互。
1. 键盘输入(按键检测 + 轴向移动)
(1)单个按键检测(按下/抬起/长按)
using UnityEngine;
public class KeyboardInputDemo : MonoBehaviour
{
void Update()
{
// 1. 按键按下(单次触发,如跳跃、射击)
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("空格键按下(单次触发)");
}
// 2. 按键抬起(单次触发)
if (Input.GetKeyUp(KeyCode.Escape))
{
Debug.Log("ESC键抬起(单次触发)");
}
// 3. 按键长按(持续触发,如加速)
if (Input.GetKey(KeyCode.LeftShift))
{
Debug.Log("左Shift长按中(持续触发)");
}
// 4. 字母/数字键检测
if (Input.GetKeyDown(KeyCode.A)) Debug.Log("A键按下");
if (Input.GetKeyDown(KeyCode.1)) Debug.Log("数字1按下");
}
}
(2)轴向输入(WASD/方向键,适合移动)
Unity 默认配置了 Horizontal(水平)和 Vertical(垂直)轴,直接获取 -1~1 的数值,支持平滑过渡:
public class PlayerMovement : MonoBehaviour
{
public float moveSpeed = 5f;
void Update()
{
// 水平轴:A/左箭头=-1,D/右箭头=1,无操作=0
float horizontal = Input.GetAxis("Horizontal");
// 垂直轴:S/下箭头=-1,W/上箭头=1,无操作=0
float vertical = Input.GetAxis("Vertical");
// 计算移动方向(normalized 避免斜向移动速度过快)
Vector3 moveDir = new Vector3(horizontal, 0, vertical).normalized;
// 平移物体(Time.deltaTime 使移动速度与帧率无关)
transform.Translate(moveDir * moveSpeed * Time.deltaTime);
}
}
- 平滑 vs 即时:
Input.GetAxis("Horizontal"):带渐变(从 0→1 有过渡),适合平滑移动。Input.GetAxisRaw("Horizontal"):无渐变(直接返回 -1/0/1),适合快速响应(如菜单切换)。
2. 鼠标输入(位置/按键/滚轮/拖拽)
(1)鼠标按键检测(左键/右键/中键)
通过索引区分按键:0=左键,1=右键,2=中键
public class MouseInputDemo : MonoBehaviour
{
void Update()
{
// 左键按下(单次触发,如点击交互)
if (Input.GetMouseButtonDown(0))
{
Debug.Log("鼠标左键按下");
}
// 右键长按(持续触发,如拖拽)
if (Input.GetMouseButton(1))
{
Debug.Log("鼠标右键长按中");
}
// 中键抬起(单次触发,如取消操作)
if (Input.GetMouseButtonUp(2))
{
Debug.Log("鼠标中键抬起");
}
}
}
(2)鼠标位置(屏幕坐标)
屏幕坐标原点在 左下角(x=0,y=0),右上角为(x=Screen.width, y=Screen.height):
void Update()
{
// 获取鼠标屏幕坐标
Vector3 mouseScreenPos = Input.mousePosition;
Debug.Log($"鼠标位置:X={mouseScreenPos.x}, Y={mouseScreenPos.y}");
// 示例:让物体跟随鼠标(2D项目)
if (Camera.main.orthographic) // 判断是否为2D相机
{
// 屏幕坐标 → 世界坐标(2D需设置z轴为0)
Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(mouseScreenPos);
mouseWorldPos.z = 0; // 2D项目避免z轴偏移
transform.position = mouseWorldPos;
}
}
(3)鼠标滚轮(缩放/滚动)
通过 Input.mouseScrollDelta.y 获取滚动量(向上=正值,向下=负值):
public class MouseScrollDemo : MonoBehaviour
{
public float scaleSpeed = 0.1f;
public Vector3 minScale = new Vector3(0.5f, 0.5f, 0.5f); // 最小缩放
public Vector3 maxScale = new Vector3(2f, 2f, 2f); // 最大缩放
void Update()
{
// 获取滚轮滚动量(y轴为垂直滚动,x轴为水平滚动(部分鼠标支持))
float scroll = Input.mouseScrollDelta.y;
// 缩放物体
transform.localScale += new Vector3(scroll * scaleSpeed, scroll * scaleSpeed, scroll * scaleSpeed);
// 限制缩放范围(避免过大/过小)
transform.localScale = Vector3.ClampMagnitude(transform.localScale, maxScale.magnitude);
transform.localScale = Vector3.Max(transform.localScale, minScale);
}
}
(4)鼠标拖拽(世界空间,需 Collider)
物体必须有 Collider(如 BoxCollider)才能响应鼠标点击,通过「按下+位置变化」实现拖拽:
public class MouseDragDemo : MonoBehaviour
{
private bool isDragging = false;
private Vector3 offset; // 鼠标与物体的偏移(避免瞬移)
// 鼠标点击物体时触发(需 Collider)
void OnMouseDown()
{
// 射线检测:将鼠标屏幕坐标转换为世界射线
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit))
{
// 计算物体中心与射线命中点的偏移
offset = transform.position - hit.point;
isDragging = true;
}
}
// 鼠标抬起时结束拖拽
void OnMouseUp()
{
isDragging = false;
}
void Update()
{
if (isDragging)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit))
{
// 保持偏移,平滑拖拽
transform.position = hit.point + offset;
}
}
}
}
二、新版 Input System(推荐复杂项目/多平台)
功能更强(支持多设备、按键重映射、自定义输入),需先安装包,适合复杂交互或多平台项目。
1. 前期配置(3步)
- 安装包:
Window → Package Manager → 搜索 Input System → 安装(安装后重启 Unity)。 - 创建输入资源:右键 Project 窗口 →
Input Actions→ 命名(如PlayerInputActions)。 - 配置输入映射(双击打开配置窗口):
- 新建
Action Map(如Player)。 - 添加 Action 并绑定按键(示例):
Action 名称 类型 绑定内容 Move Value→Vector2 WASD + 方向键(Keyboard/W/A/S/D + Arrow Keys) Jump Button 空格键(Keyboard/Space) LeftClick Button 鼠标左键(Mouse/Left Button) MousePos Value→Vector2 鼠标位置(Mouse/Position) MouseScroll Value→Vector2 鼠标滚轮(Mouse/Scroll)
- 新建
2. 代码中使用(回调/实时读取)
(1)键盘输入(移动 + 跳跃)
通过回调函数响应输入,更灵活:
using UnityEngine;
using UnityEngine.InputSystem;
public class NewInputKeyboardDemo : MonoBehaviour
{
private PlayerInputActions inputActions;
public float moveSpeed = 5f;
void Awake()
{
// 初始化输入资源
inputActions = new PlayerInputActions();
// 绑定跳跃回调(按下时触发)
inputActions.Player.Jump.performed += OnJump;
// 绑定移动回调(持续触发,输入变化时调用)
inputActions.Player.Move.performed += OnMove;
inputActions.Player.Move.canceled += OnMoveCanceled; // 移动停止时触发
}
// 跳跃逻辑
void OnJump(InputAction.CallbackContext context)
{
Debug.Log("跳跃触发(新版Input)");
GetComponent<Rigidbody>().AddForce(Vector3.up * 5f, ForceMode.Impulse);
}
// 移动逻辑
void OnMove(InputAction.CallbackContext context)
{
// 读取移动输入(Vector2:x=水平,y=垂直)
Vector2 moveInput = context.ReadValue<Vector2>();
Vector3 moveDir = new Vector3(moveInput.x, 0, moveInput.y).normalized;
transform.Translate(moveDir * moveSpeed * Time.deltaTime);
}
// 移动停止时的逻辑
void OnMoveCanceled(InputAction.CallbackContext context)
{
Debug.Log("移动停止");
}
// 启用/禁用输入(避免后台触发)
void OnEnable() => inputActions.Enable();
void OnDisable() => inputActions.Disable();
}
(2)鼠标输入(位置/点击/滚轮)
using UnityEngine;
using UnityEngine.InputSystem;
public class NewInputMouseDemo : MonoBehaviour
{
private PlayerInputActions inputActions;
void Awake()
{
inputActions = new PlayerInputActions();
// 鼠标左键点击回调
inputActions.Player.LeftClick.performed += ctx => Debug.Log("鼠标左键点击(新版Input)");
// 鼠标滚轮回调
inputActions.Player.MouseScroll.performed += ctx =>
{
Vector2 scroll = ctx.ReadValue<Vector2>();
Debug.Log($"滚轮滚动:Y={scroll.y}");
// 缩放逻辑(同旧版)
transform.localScale += new Vector3(scroll.y * 0.1f, scroll.y * 0.1f, scroll.y * 0.1f);
};
}
void Update()
{
// 实时读取鼠标位置(屏幕坐标)
Vector2 mousePos = inputActions.Player.MousePos.ReadValue<Vector2>();
Debug.Log($"鼠标位置(新版):X={mousePos.x}, Y={mousePos.y}");
}
void OnEnable() => inputActions.Enable();
void OnDisable() => inputActions.Disable();
}
三、关键注意事项(避坑指南)
-
物体不响应鼠标事件?
- 必须给物体添加
Collider(如 BoxCollider、SphereCollider),且Is Trigger未勾选(或勾选后用OnTrigger事件)。 - 确保相机是「MainCamera」(或代码中指定正确相机,如
Camera.main替换为自定义相机引用)。
- 必须给物体添加
-
坐标转换问题(屏幕→世界)
- 3D 项目:必须用
Camera.ScreenPointToRay(射线检测)获取世界坐标,不能直接用ScreenToWorldPoint(会忽略深度)。 - 2D 项目:
ScreenToWorldPoint需手动设置 z 轴(如mouseWorldPos.z = 0),否则物体可能消失。
- 3D 项目:必须用
-
输入延迟/不流畅?
- 旧版:
Input.GetAxis有平滑过渡,如需即时响应改用Input.GetAxisRaw。 - 新版:Action 类型选择「Button」(单次触发)或「Value」(持续输入),避免回调逻辑过重。
- 旧版:
-
多按键冲突?
- 用
Input.GetKeyDown时,避免同时检测多个按键(如A和D同时按下),可通过Input.GetAxis自动处理(返回 0)。
- 用
总结
| 场景 | 推荐方案 | 核心优势 |
|---|---|---|
| 快速原型/简单交互 | 旧版 Input Manager | 无需配置,代码简洁 |
| 复杂项目/多平台 | 新版 Input System | 支持重映射、多设备,扩展性强 |
| 移动类输入(WASD) | 轴向输入(GetAxis) | 平滑过渡,避免斜向速度过快 |
| 鼠标拖拽/点击 | Collider + 射线检测 | 精准响应物体交互 |
根据项目复杂度选择输入系统,核心逻辑可直接复用上述代码,如需扩展(如自定义按键、多设备支持),可进一步配置 Input 系统的参数。