Hello everybody ;
I’m sorry by advance for my bad english because i’m french ![]()
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 ![]()
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 .
![]()