本文已参与「新人创作礼」活动,一起开启掘金创作之路。
关于input system的导入及相关配置,请先参考拙作 unity 最新输入系统Input system简介,并用其设置Xbox(plus:unity package导入详解) 本文只讲解input Actions的配置
针对车的配置总体如下:
Next Vehicle(用于切换车型、可选)、Reset Vehicle(用于重置汽车,可选)、Handbrake(手刹)都是Button类型
Acceration(驱动) 和 Steering Angle(车轮角度)都是Value类型,Axis控制类型
值得说一下的是,如果你也用了手柄,要想倒车的话,就得像下面一样加个Invert
这样能使传输值由(0,1)转为(-1,0)
保存之后就是代码部分了。
下面是官方给的一个汽车脚本,我做了部分注释与注释的汉化:
using UnityEngine;
using System;
[Serializable]
public enum DriveType
{
RearWheelDrive,
FrontWheelDrive,
AllWheelDrive
}
public class WheelDrive : MonoBehaviour
{
[Tooltip("Maximum steering angle of the wheels")]
public float maxAngle = 30f;
[Tooltip("Maximum torque applied to the driving wheels")]
public float maxTorque = 300f;
[Tooltip("Maximum brake torque applied to the driving wheels")]
public float brakeTorque = 30000f;
[Tooltip("If you need the visual wheels to be attached automatically, drag the wheel shape here.")]
public GameObject wheelShape;
[Tooltip("The vehicle's speed when the physics engine can use different amount of sub-steps (in m/s).")]
public float criticalSpeed = 5f;
[Tooltip("Simulation sub-steps when the speed is above critical.")]
public int stepsBelow = 5;
[Tooltip("Simulation sub-steps when the speed is below critical.")]
public int stepsAbove = 1;
[Tooltip("The vehicle's drive type: rear-wheels drive, front-wheels drive or all-wheels drive.")]
public DriveType driveType;
private WheelCollider[] m_Wheels;
float handBrake, angle, torque;
// 找到对象下的所有WheelCollider组件
void Start()
{
m_Wheels = GetComponentsInChildren<WheelCollider>();
foreach (WheelCollider wheel in m_Wheels)
{
// Create wheel shapes only when needed.
if (wheelShape != null)
{
GameObject ws = Instantiate(wheelShape);
ws.transform.parent = wheel.transform;
}
}
}
// This is a really simple approach to updating wheels.
// We simulate a rear wheel drive car and assume that the car is perfectly symmetric at local zero.
// This helps us to figure our which wheels are front ones and which are rear.
void Update()
{
m_Wheels[0].ConfigureVehicleSubsteps(criticalSpeed, stepsBelow, stepsAbove);
angle = maxAngle * Input.GetAxis("Horizontal");
torque = maxTorque * Input.GetAxis("Vertical");
handBrake = Input.GetKey(KeyCode.X) ? brakeTorque : 0;
foreach (WheelCollider wheel in m_Wheels)
{
// A simple car where front wheels steer while rear ones drive.
if (wheel.transform.localPosition.z > 0) //前轮
wheel.steerAngle = angle;
if (wheel.transform.localPosition.z < 0) //后轮
{
wheel.brakeTorque = handBrake;
}
//是后轮且不是前轮驱动模式
if (wheel.transform.localPosition.z < 0 && driveType != DriveType.FrontWheelDrive)
{
//加驱动
wheel.motorTorque = torque;
}
//是前轮且不是后轮驱动模式
if (wheel.transform.localPosition.z >= 0 && driveType != DriveType.RearWheelDrive)
{
wheel.motorTorque = torque;
}
// 车轮根据wheelCollider同步转动
if (wheelShape)
{
Quaternion q;
Vector3 p;
wheel.GetWorldPose(out p, out q);
// Assume that the only child of the wheelcollider is the wheel shape.
Transform shapeTransform = wheel.transform.GetChild(0);
if (wheel.name == "a0l" || wheel.name == "a1l" || wheel.name == "a2l")
{
shapeTransform.rotation = q * Quaternion.Euler(0, 180, 0);
shapeTransform.position = p;
}
else
{
shapeTransform.position = p;
shapeTransform.rotation = q;
}
}
}
}
}
为了用将input manager更新为input system,主要有三点改动:
①多了个using UnityEngine.InputSystem;
②加入了如下代码
public InputActionAsset primaryActions;
InputActionMap gamePlayActionMap;
InputAction handBrakeInputAction;
InputAction steerAngleInputAction;
InputAction accelerateionInputAction;
private void Awake()
{
gamePlayActionMap = primaryActions.FindActionMap("GamePlay");
handBrakeInputAction = gamePlayActionMap.FindAction("HandBrake");
steerAngleInputAction = gamePlayActionMap.FindAction("Steering Angle");
accelerateionInputAction = gamePlayActionMap.FindAction("Acceleration");
handBrakeInputAction.performed += ctx => GetHandBrakeInput(ctx.ReadValue<float>());
handBrakeInputAction.canceled += ctx => GetHandBrakeInput(ctx.ReadValue<float>());
steerAngleInputAction.performed += GetAngleInput; //为了尝试多种传参方式
steerAngleInputAction.canceled += GetAngleInput;
accelerateionInputAction.performed += ctx => GetTorqueInput(ctx.ReadValue<float>());
accelerateionInputAction.canceled += ctx => GetTorqueInput(ctx.ReadValue<float>());
}
//private void GetHandBrakeInput(InputAction.CallbackContext context)
//{
// handBrake = context.ReadValue<float>() * brakeTorque;
//}
private void GetHandBrakeInput(float handBrakeValue)
{
handBrake = handBrakeValue * brakeTorque;
}
//private void GetAngleInput(float angleValue)
//{
// angle = angleValue * maxAngle;
// Debug.Log(angleValue);
//}
private void GetAngleInput(InputAction.CallbackContext context)
{
angle = context.ReadValue<float>() * maxAngle;
Debug.Log(context.ReadValue<float>());
}
private void GetTorqueInput(float torqueValue)
{
torque = torqueValue * maxTorque;
}
/// <summary>
/// 当对象已启用并处于活跃状态时调用
/// </summary>
private void OnEnable()
{
handBrakeInputAction.Enable();
steerAngleInputAction.Enable();
accelerateionInputAction.Enable();
}
/// <summary>
/// 当对象被禁用或处于非活跃状态时调用
/// </summary>
private void OnDisable()
{
handBrakeInputAction.Disable();
steerAngleInputAction.Disable();
accelerateionInputAction.Disable();
}
③把原本input manager的传参代码注释掉
下面是改动过后的完整代码
using UnityEngine;
using System;
using UnityEngine.InputSystem;
[Serializable]
public enum DriveType
{
RearWheelDrive,
FrontWheelDrive,
AllWheelDrive
}
public class WheelDrive : MonoBehaviour
{
[Tooltip("Maximum steering angle of the wheels")]
public float maxAngle = 30f;
[Tooltip("Maximum torque applied to the driving wheels")]
public float maxTorque = 300f;
[Tooltip("Maximum brake torque applied to the driving wheels")]
public float brakeTorque = 30000f;
[Tooltip("If you need the visual wheels to be attached automatically, drag the wheel shape here.")]
public GameObject wheelShape;
[Tooltip("The vehicle's speed when the physics engine can use different amount of sub-steps (in m/s).")]
public float criticalSpeed = 5f;
[Tooltip("Simulation sub-steps when the speed is above critical.")]
public int stepsBelow = 5;
[Tooltip("Simulation sub-steps when the speed is below critical.")]
public int stepsAbove = 1;
[Tooltip("The vehicle's drive type: rear-wheels drive, front-wheels drive or all-wheels drive.")]
public DriveType driveType;
private WheelCollider[] m_Wheels;
float handBrake, angle, torque;
public InputActionAsset primaryActions;
InputActionMap gamePlayActionMap;
InputAction handBrakeInputAction;
InputAction steerAngleInputAction;
InputAction accelerateionInputAction;
private void Awake()
{
gamePlayActionMap = primaryActions.FindActionMap("GamePlay");
handBrakeInputAction = gamePlayActionMap.FindAction("HandBrake");
steerAngleInputAction = gamePlayActionMap.FindAction("Steering Angle");
accelerateionInputAction = gamePlayActionMap.FindAction("Acceleration");
handBrakeInputAction.performed += ctx => GetHandBrakeInput(ctx.ReadValue<float>());
handBrakeInputAction.canceled += ctx => GetHandBrakeInput(ctx.ReadValue<float>());
steerAngleInputAction.performed += GetAngleInput; //为了尝试多种传参方式
steerAngleInputAction.canceled += GetAngleInput;
accelerateionInputAction.performed += ctx => GetTorqueInput(ctx.ReadValue<float>());
accelerateionInputAction.canceled += ctx => GetTorqueInput(ctx.ReadValue<float>());
}
//private void GetHandBrakeInput(InputAction.CallbackContext context)
//{
// handBrake = context.ReadValue<float>() * brakeTorque;
//}
private void GetHandBrakeInput(float handBrakeValue)
{
handBrake = handBrakeValue * brakeTorque;
}
//private void GetAngleInput(float angleValue)
//{
// angle = angleValue * maxAngle;
// Debug.Log(angleValue);
//}
private void GetAngleInput(InputAction.CallbackContext context)
{
angle = context.ReadValue<float>() * maxAngle;
Debug.Log(context.ReadValue<float>());
}
private void GetTorqueInput(float torqueValue)
{
torque = torqueValue * maxTorque;
}
/// <summary>
/// 当对象已启用并处于活跃状态时调用
/// </summary>
private void OnEnable()
{
handBrakeInputAction.Enable();
steerAngleInputAction.Enable();
accelerateionInputAction.Enable();
}
/// <summary>
/// 当对象被禁用或处于非活跃状态时调用
/// </summary>
private void OnDisable()
{
handBrakeInputAction.Disable();
steerAngleInputAction.Disable();
accelerateionInputAction.Disable();
}
// 找到对象下的所有WheelCollider组件
void Start()
{
m_Wheels = GetComponentsInChildren<WheelCollider>();
/*
//for (int i = 0; i < m_Wheels.Length; ++i)
//{
// var wheel = m_Wheels[i];
// // Create wheel shapes only when needed.
// if (wheelShape != null)
// {
// var ws = Instantiate(wheelShape);
// ws.transform.parent = wheel.transform;
// }
//}
*/
foreach (WheelCollider wheel in m_Wheels)
{
// Create wheel shapes only when needed.
if (wheelShape != null)
{
GameObject ws = Instantiate(wheelShape);
ws.transform.parent = wheel.transform;
}
}
}
// This is a really simple approach to updating wheels.
// We simulate a rear wheel drive car and assume that the car is perfectly symmetric at local zero.
// This helps us to figure our which wheels are front ones and which are rear.
void Update()
{
m_Wheels[0].ConfigureVehicleSubsteps(criticalSpeed, stepsBelow, stepsAbove);
//angle = maxAngle * Input.GetAxis("Horizontal");
//torque = maxTorque * Input.GetAxis("Vertical");
//handBrake = Input.GetKey(KeyCode.X) ? brakeTorque : 0;
foreach (WheelCollider wheel in m_Wheels)
{
// A simple car where front wheels steer while rear ones drive.
if (wheel.transform.localPosition.z > 0) //前轮
wheel.steerAngle = angle;
if (wheel.transform.localPosition.z < 0) //后轮
{
wheel.brakeTorque = handBrake;
}
//是后轮且不是前轮驱动模式
if (wheel.transform.localPosition.z < 0 && driveType != DriveType.FrontWheelDrive)
{
//加驱动
wheel.motorTorque = torque;
}
//是前轮且不是后轮驱动模式
if (wheel.transform.localPosition.z >= 0 && driveType != DriveType.RearWheelDrive)
{
wheel.motorTorque = torque;
}
// 车轮根据wheelCollider同步转动
if (wheelShape)
{
Quaternion q;
Vector3 p;
wheel.GetWorldPose(out p, out q);
// Assume that the only child of the wheelcollider is the wheel shape.
Transform shapeTransform = wheel.transform.GetChild(0);
if (wheel.name == "a0l" || wheel.name == "a1l" || wheel.name == "a2l")
{
shapeTransform.rotation = q * Quaternion.Euler(0, 180, 0);
shapeTransform.position = p;
}
else
{
shapeTransform.position = p;
shapeTransform.rotation = q;
}
}
}
}
}
还有一点需要注意:该脚本在使用之前需要先给它安排车轮的预制体(不然你可能玩的是“真 · 飞车"),和配置好的Input Actions(我命名为了Primary Actions)