[HELP] VR Steering Wheel

Hello everybody ;

I’m sorry by advance for my bad english because i’m french :wink:
I want create a small VR game for oculus , vive … and i need to solve my little problem .
i want when i grab and turn my steering wheel (in car FPS view) the wheels turn too .
to do this i use a wheel script from VRTK but i understand nothing inside :frowning:

Can you please help me to solve this problem ?

here is the wheel script i add it to the steering wheel gameobject :

// Wheel|Controls3D|100062
namespace VRTK
{
    using UnityEngine;
    using GrabAttachMechanics;

    /// <summary>
    /// Attaching the script to a game object will allow the user to interact with it as if it were a spinnable wheel.
    /// </summary>
    /// <remarks>
    /// The script will instantiate the required Rigidbody and Interactable components automatically in case they do not exist yet.
    /// </remarks>
    /// <example>
    /// `VRTK/Examples/025_Controls_Overview` has a collection of wheels that can be rotated by grabbing with the controller and then rotating the controller in the desired direction.
    /// </example>
    [AddComponentMenu("VRTK/Scripts/Controls/3D/VRTK_Wheel")]
    public class VRTK_Wheel : VRTK_Control
    {
        public enum GrabTypes
        {
            TrackObject,
            RotatorTrack
        }

        [Tooltip("An optional game object to which the wheel will be connected. If the game object moves the wheel will follow along.")]
        public GameObject connectedTo;
        [Tooltip("The grab attach mechanic to use. Track Object allows for rotations of the controller, Rotator Track allows for grabbing the wheel and spinning it.")]
        public GrabTypes grabType = GrabTypes.TrackObject;
        [Tooltip("The maximum distance the grabbing controller is away from the wheel before it is automatically released.")]
        public float detatchDistance = 0.5f;
        [Tooltip("The minimum value the wheel can be set to.")]
        public float minimumValue = 0f;
        [Tooltip("The maximum value the wheel can be set to.")]
        public float maximumValue = 10f;
        [Tooltip("The increments in which values can change.")]
        public float stepSize = 1f;
        [Tooltip("If this is checked then when the wheel is released, it will snap to the step rotation.")]
        public bool snapToStep = false;
        [Tooltip("The amount of friction the wheel will have when it is grabbed.")]
        public float grabbedFriction = 25f;
        [Tooltip("The amount of friction the wheel will have when it is released.")]
        public float releasedFriction = 10f;
        [Range(0f, 359f)]
        [Tooltip("The maximum angle the wheel has to be turned to reach it's maximum value.")]
        public float maxAngle = 359f;
        [Tooltip("If this is checked then the wheel cannot be turned beyond the minimum and maximum value.")]
        public bool lockAtLimits = false;

        protected float angularVelocityLimit = 150f;
        protected float springStrengthValue = 150f;
        protected float springDamperValue = 5f;
        protected Quaternion initialLocalRotation;
        protected Rigidbody wheelRigidbody;
        protected HingeJoint wheelHinge;
        protected bool wheelHingeCreated = false;
        protected bool initialValueCalculated = false;
        protected float springAngle;

        protected override void InitRequiredComponents()
        {
            initialLocalRotation = transform.localRotation;
            InitWheel();
        }

        protected override bool DetectSetup()
        {
            if (wheelHingeCreated)
            {
                wheelHinge.anchor = Vector3.up;
                wheelHinge.axis = Vector3.up;

                if (connectedTo)
                {
                    wheelHinge.connectedBody = connectedTo.GetComponent<Rigidbody>();
                }
            }

            return true;
        }

        protected override ControlValueRange RegisterValueRange()
        {
            return new ControlValueRange()
            {
                controlMin = minimumValue,
                controlMax = maximumValue
            };
        }

        protected override void HandleUpdate()
        {
            CalculateValue();
            if (lockAtLimits && !initialValueCalculated)
            {
                transform.localRotation = initialLocalRotation;
                initialValueCalculated = true;
            }
        }

        protected virtual void InitWheel()
        {
            SetupRigidbody();
            SetupHinge();
            SetupInteractableObject();
        }

        protected virtual void SetupRigidbody()
        {
            wheelRigidbody = GetComponent<Rigidbody>();
            if (wheelRigidbody == null)
            {
                wheelRigidbody = gameObject.AddComponent<Rigidbody>();
                wheelRigidbody.angularDrag = releasedFriction;
            }
            wheelRigidbody.isKinematic = false;
            wheelRigidbody.useGravity = false;

            if (connectedTo)
            {
                Rigidbody connectedToRigidbody = connectedTo.GetComponent<Rigidbody>();
                if (connectedToRigidbody == null)
                {
                    connectedToRigidbody = connectedTo.AddComponent<Rigidbody>();
                    connectedToRigidbody.useGravity = false;
                    connectedToRigidbody.isKinematic = true;
                }
            }
        }

        protected virtual void SetupHinge()
        {
            wheelHinge = GetComponent<HingeJoint>();
            if (wheelHinge == null)
            {
                wheelHinge = gameObject.AddComponent<HingeJoint>();
                wheelHingeCreated = true;
            }

            SetupHingeRestrictions();
        }

        protected virtual void SetupHingeRestrictions()
        {
            var minJointLimit = 0f;
            var maxJointLimit = maxAngle;
            var limitOffset = maxAngle - 180f;

            if (limitOffset > 0f)
            {
                minJointLimit -= limitOffset;
                maxJointLimit = 180f;
            }

            if (lockAtLimits)
            {
                wheelHinge.useLimits = true;
                JointLimits wheelLimits = new JointLimits();
                wheelLimits.min = minJointLimit;
                wheelLimits.max = maxJointLimit;
                wheelHinge.limits = wheelLimits;
                Vector3 adjustedLimitsAngle = transform.localEulerAngles;

                switch (Mathf.RoundToInt(initialLocalRotation.eulerAngles.z))
                {
                    case 0:
                        adjustedLimitsAngle = new Vector3(transform.localEulerAngles.x, transform.localEulerAngles.y - minJointLimit, transform.localEulerAngles.z);
                        break;
                    case 90:
                        adjustedLimitsAngle = new Vector3(transform.localEulerAngles.x + minJointLimit, transform.localEulerAngles.y, transform.localEulerAngles.z);
                        break;
                    case 180:
                        adjustedLimitsAngle = new Vector3(transform.localEulerAngles.x, transform.localEulerAngles.y + minJointLimit, transform.localEulerAngles.z);
                        break;
                }
                transform.localEulerAngles = adjustedLimitsAngle;
                initialValueCalculated = false;
            }
        }

        protected virtual void ConfigureHingeSpring()
        {
            JointSpring snapSpring = new JointSpring();
            snapSpring.spring = springStrengthValue;
            snapSpring.damper = springDamperValue;
            snapSpring.targetPosition = springAngle + wheelHinge.limits.min;
            wheelHinge.spring = snapSpring;
        }

        protected virtual void SetupInteractableObject()
        {
            VRTK_InteractableObject wheelInteractableObject = GetComponent<VRTK_InteractableObject>();
            if (wheelInteractableObject == null)
            {
                wheelInteractableObject = gameObject.AddComponent<VRTK_InteractableObject>();
            }
            wheelInteractableObject.isGrabbable = true;

            VRTK_TrackObjectGrabAttach attachMechanic;

            if (grabType == GrabTypes.TrackObject)
            {
                attachMechanic = gameObject.AddComponent<VRTK_TrackObjectGrabAttach>();
                if (lockAtLimits)
                {
                    attachMechanic.velocityLimit = 0f;
                    attachMechanic.angularVelocityLimit = angularVelocityLimit;
                }
            }
            else
            {
                attachMechanic = gameObject.AddComponent<VRTK_RotatorTrackGrabAttach>();
            }

            attachMechanic.precisionGrab = true;
            attachMechanic.detachDistance = detatchDistance;

            wheelInteractableObject.grabAttachMechanicScript = attachMechanic;

            wheelInteractableObject.secondaryGrabActionScript = gameObject.AddComponent<SecondaryControllerGrabActions.VRTK_SwapControllerGrabAction>();
            wheelInteractableObject.stayGrabbedOnTeleport = false;

            wheelInteractableObject.InteractableObjectGrabbed += WheelInteractableObjectGrabbed;
            wheelInteractableObject.InteractableObjectUngrabbed += WheelInteractableObjectUngrabbed;
        }

        protected virtual void WheelInteractableObjectGrabbed(object sender, InteractableObjectEventArgs e)
        {
            wheelRigidbody.angularDrag = grabbedFriction;
            wheelHinge.useSpring = false;
        }

        protected virtual void WheelInteractableObjectUngrabbed(object sender, InteractableObjectEventArgs e)
        {
            wheelRigidbody.angularDrag = releasedFriction;
            if (snapToStep)
            {
                wheelHinge.useSpring = true;
                ConfigureHingeSpring();
            }
        }

        protected virtual void CalculateValue()
        {
            ControlValueRange controlValueRange = RegisterValueRange();
            float angle;
            Vector3 axis;

            Quaternion rotationDelta = transform.localRotation * Quaternion.Inverse(initialLocalRotation);
            rotationDelta.ToAngleAxis(out angle, out axis);

            float calculatedValue = Mathf.Round((controlValueRange.controlMin + Mathf.Clamp01(angle / maxAngle) * (controlValueRange.controlMax - controlValueRange.controlMin)) / stepSize) * stepSize;

            float flatValue = calculatedValue - controlValueRange.controlMin;
            float controlRange = controlValueRange.controlMax - controlValueRange.controlMin;
            springAngle = (flatValue / controlRange) * maxAngle;

            value = calculatedValue;
        }
    }
}

with this one i can turn the steering wheel but the wheels doesn’t turn.

and here is the script steeringwheel control to turn wheels :

using UnityEngine;
using System.Collections;

//Class for steering vehicles
public class SteeringControl : MonoBehaviour
{
    Transform tr;
    VehicleParent vp;
    public float steerRate = 0.1f;
    float steerAmount;

    [Tooltip("Curve for limiting steer range based on speed, x-axis = speed, y-axis = multiplier")]
    public AnimationCurve steerCurve = AnimationCurve.Linear(0, 1, 30, 0.1f);
    public bool limitSteer = true;

    [Tooltip("Horizontal stretch of the steer curve")]
    public float steerCurveStretch = 1;
    public bool applyInReverse = true;//Limit steering in reverse?
    public Suspension[] steeredWheels;

    [Header("Visual")]

    public bool rotate;
    public float maxDegreesRotation;
    public float rotationOffset;
    float steerRot;

    void Start()
    {
        tr = transform;
        vp = transform.root.GetComponent<VehicleParent>();
        steerRot = rotationOffset;
    }
  
    void FixedUpdate()
    {
        float rbSpeed = vp.localVelocity.z / steerCurveStretch;
        float steerLimit = limitSteer ? steerCurve.Evaluate(applyInReverse ? Mathf.Abs(rbSpeed) : rbSpeed) : 1;
        steerAmount = vp.steerInput * steerLimit;

        //Set steer angles in wheels
        foreach (Suspension curSus in steeredWheels)
        {
            curSus.steerAngle = Mathf.Lerp(curSus.steerAngle, steerAmount * curSus.steerFactor * (curSus.steerEnabled ? 1 : 0) * (curSus.steerInverted ? -1 : 1), steerRate * Time.timeScale);
        }
    }

    void Update()
    {
        if (rotate)
        {
            steerRot = Mathf.Lerp(steerRot, steerAmount * maxDegreesRotation + rotationOffset, steerRate * Time.timeScale);
            tr.localEulerAngles = new Vector3(tr.localEulerAngles.x, tr.localEulerAngles.y, steerRot);
        }
    }
}

and with this script i can turn wheels with thumbstick .

Someone can tell me what i need to change in the second script to check the angle value of my steering wheel ?

Thanks by advance for your time guys .
:wink:

Nobody ? please :frowning:

Hi there, did you find any solution?

Looking for same solution you are close. Need to combine the wheels to turn in unison with steering wheel.