【25 AGLab 社团课程】引擎与技术基础——【第三节】Unity c#脚本响应玩家输入
【第二节课后练习解析】
public class Class2_CubeRot_answer : MonoBehaviour
{
// 速率控制
// 使用 Public 公开的基础变量可以在检查器面板上控制
public float Rate = 20f;
// 类变量,存储要转动的物体
private GameObject Cube;
private void Awake()
{
// 唤醒时获取要转动的物体
// this.gameObject => 脚本挂载的物体
Cube = this.gameObject;
}
void FixedUpdate()
{
// 在每一帧旋转物体
// Time.deltaTime => 距离上一帧经过的时间
// 每秒旋转 * 这两帧经过多少秒(Time.deltaTime) => 这一帧要转多大
Cube.transform.eulerAngles += new Vector3(0, Rate, 0) * Time.deltaTime;
// 在 Rate 前加上一个 “-” 表示向相反方向转动
// Cube.transform.eulerAngles += new Vector3(0, -Rate, 0) * Time.deltaTime;
}
}
【前置知识点】
C# 判断 - 多态性:C# 判断 | 菜鸟教程

新老输入系统简要介绍
Unity 常用的输入系统分为 (老)InputManager 和 (新)InputSystem。
老系统功能比较简单,可在下图位置看到详细配置,需通过 Input.Get 系列API主动的获取按键状态,新增修改按键与实现多人游戏时较为麻烦。

新系统功能比较齐全,需手动从包管理器获取(见下图1),可通过配置 InputActions 的形式实现在 手柄,键盘,鼠标 等不同输入下的适配(见下图2),功能齐全但实现起来较为复杂。


老输入系统读取键盘输入
新输入系统讲解起来有点复杂了,我们在本次课程中还是先使用老输入系统实现。
我们先来看一下输入管理器中的预设,在默认情况下输入管理器给我们提供了 “水平” 和 “垂直” 两个轴的预设:

为了理解 输入轴 这个概念,我们做以下图:
假设我们有两个人在抢一个小球,他们分别站在两边,用两个绳子分别拉着小球:

这时倘若我们把 左边的人所在位置定为 -1 ,右边的人所在位置定为 1 , 球初始所在位置定为 0 ,并以此做一个数轴,就可以通过数轴描述最终球的位置:

回到 输入管理器中的预设 点开任意一个轴预设可以看到,有 肯定按钮,否定按钮 和对应的 Alt:

肯定按钮就相当于站在 1位置 上的人,如果只按下肯定按钮 小球就会向 1位置 移动,获取到轴的值也就趋近于 1。
否定按钮就相当于站在 -1位置 上的人,如果只按下否定按钮 小球就会向 -1位置 移动,获取到轴的值也就趋近于 -1。
对应的Alt按钮就相当于 对应人的 一个别名,同时按下 肯定按钮 和 Alt肯定按钮 还是一个人拉 因此并不会因此以两倍速度拉向1。
接下来我们创建一个 Class3_CubeController 脚本,来到脚本中 我们应该怎么样获取对应轴的值呢?
在 输入管理器对应轴的预设 中有一项属性 “名称”

我们可以通过以下API+名称获取轴的值
Input.GetAxis("轴的名称");
因此我们可以有:
void Update()
{
// 获取 水平 轴的输入
float hori = Input.GetAxis("Horizontal");
// 获取 垂直 轴的输入
float vert = Input.GetAxis("Vertical");
}
接下来我们像上节课一样 公开一个速度值 并将 水平 & 垂直输入 * 速度 后应用到小方块的位置上:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Class3_CubeController : MonoBehaviour
{
public float MoveSpeed = 5f;
private GameObject Cube;
private void Awake()
{
Cube = this.gameObject;
}
void Update()
{
// 获取 水平 轴的输入
float hori = Input.GetAxis("Horizontal");
// 获取 垂直 轴的输入
float vert = Input.GetAxis("Vertical");
// 为什么这里用的是 Time.deltaTime 而 Class2 用的是 Time.fixedDeltaTime 呢?[仅作了解]
// 因为这里是在 Update (每一渲染帧)中调用,Time.deltaTime 获取的是渲染帧的间隔
// Class2 的脚本是在 FixedUpdate(每一物理帧)中调用,Time.fixedDeltaTime 获取的是物理帧间隔
// 获取输入一般在 Update,物理控制一般在 FixedUpdate
Cube.transform.position += new Vector3(hori, vert, 0).normalized * MoveSpeed * Time.deltaTime;
}
}
就已经可以 实现读取键盘输入 并控制小方块移动啦!
我们接下来再尝试读取单个按键输入,并实现小方块的冲刺效果
先来梳理一下我们要实现的逻辑:
- 当玩家按下 Space键(空格键)的时候触发冲刺
- 冲刺的方向 与 当前移动方向一致
读取单个按键我们可以通过以下API实现
Input.GetKeyDown(按键);
因此我们可以通过判断语句实现以下逻辑:
if (Input.GetKeyDown(KeyCode.Space))
{
// 向移动方向冲刺
}
else
{
// 正常移动
Cube.transform.position += new Vector3(hori, vert, 0).normalized * MoveSpeed * Time.deltaTime;
}
那么怎么实现冲刺呢?
我们的冲刺可以看作短时间向移动方向移动很大一段距离?并且好像我们需要控制的是冲刺的距离而不是冲刺的速度?
因此可以通过 当前位置 += 冲刺方向 * 冲刺距离 实现,还是一样我们公开一个变量来控制冲刺距离:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Class3_CubeController : MonoBehaviour
{
public float MoveSpeed = 5f; // 移动速度
public float DashDist = 2f; // 冲刺距离
private GameObject Cube;
private void Awake()
{
Cube = this.gameObject;
}
// 为什么这里用的是 Time.deltaTime 而 Class2 用的是 Time.fixedDeltaTime 呢?[仅作了解]
// 因为这里是在 Update (每一渲染帧)中调用,Time.deltaTime 获取的是渲染帧的间隔
// Class2 的脚本是在 FixedUpdate(每一物理帧)中调用,Time.fixedDeltaTime 获取的是物理帧间隔
// 获取输入一般在 Update,物理控制一般在 FixedUpdate
void Update()
{
// 获取 水平 轴的输入
float hori = Input.GetAxis("Horizontal");
// 获取 垂直 轴的输入
float vert = Input.GetAxis("Vertical");
if (Input.GetKeyDown(KeyCode.Space))
{
// 向移动方向冲刺
Cube.transform.position += new Vector3(hori, vert, 0).normalized * DashDist;
}
else
{
// 正常移动
Cube.transform.position += new Vector3(hori, vert, 0).normalized * MoveSpeed * Time.deltaTime;
// 这里使用 .normalized 归一化是为了保证向各个方向移动速率一致
}
}
}
就已经实现读取键盘输入控制小方块的移动和冲刺啦!
【课后练习】
1、更改冲刺的触发为 LeftShift 键【提交代码文件】
2、(可选)冲刺添加冷却时间(3s)【提交代码文件】
更多推荐


所有评论(0)