unity 使用input system更新input manager的汽车脚本

4,640 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

关于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) 在这里插入图片描述