namespace VRTK.Prefabs.Interactions.Controllables
{
using UnityEngine;
using System.Collections.Generic;
using Malimbe.XmlDocumentationAttribute;
using Malimbe.PropertySerializationAttribute;
using Malimbe.BehaviourStateRequirementMethod;
using Zinnia.Data.Attribute;
///
/// A rotational drive that utilizes a physics joint to control the rotational angle.
///
public class RotationalJointDrive : RotationalDrive
{
#region Joint Settings
///
/// The joint being used to drive the rotation.
///
[Serialized]
[field: Header("Joint Settings"), DocumentedByXml, Restricted]
public HingeJoint Joint { get; protected set; }
///
/// The parent of the joint.
///
[Serialized]
[field: DocumentedByXml, Restricted]
public GameObject JointContainer { get; protected set; }
#endregion
///
/// The that the joint is using.
///
protected Rigidbody jointRigidbody;
///
/// The motor data to set on the joint.
///
protected JointMotor jointMotor;
///
/// A reusable collection to hold the active state of children of the s that are adjusted.
///
protected readonly List rigidbodyChildrenActiveStates = new List();
///
[RequiresBehaviourState]
public override Vector3 CalculateDriveAxis(DriveAxis.Axis driveAxis)
{
Vector3 axisDirection = base.CalculateDriveAxis(driveAxis);
Joint.axis = axisDirection * -1f;
return axisDirection;
}
///
[RequiresBehaviourState]
public override void CalculateHingeLocation(Vector3 newHingeLocation)
{
Joint.anchor = newHingeLocation;
SetJointContainerPosition();
}
///
[RequiresBehaviourState]
public override void ConfigureAutoDrive(bool autoDrive)
{
Joint.useMotor = autoDrive;
}
///
public override void ApplyExistingAngularVelocity(float multiplier = 1f)
{
jointRigidbody.angularVelocity = AxisDirection * pseudoAngularVelocity * multiplier;
}
///
protected override void SetUpInternals()
{
jointMotor.force = Joint.motor.force;
jointRigidbody = Joint.GetComponent();
ConfigureAutoDrive(Facade.MoveToTargetValue);
base.SetUpInternals();
}
///
protected override Transform GetDriveTransform()
{
return Joint.transform;
}
///
protected override void ProcessAutoDrive(float driveSpeed)
{
jointMotor.targetVelocity = driveSpeed;
Joint.motor = jointMotor;
}
///
protected override void AttemptApplyLimits()
{
if (!Joint.useLimits && ApplyLimits())
{
jointRigidbody.velocity = Vector3.zero;
jointRigidbody.angularVelocity = Vector3.zero;
}
}
///
/// Sets the position based on the joint anchor.
///
protected virtual void SetJointContainerPosition()
{
// Disable any child rigidbody GameObjects of the joint to prevent the anchor position updating their position.
Rigidbody[] rigidbodyChildren = Joint.GetComponentsInChildren();
rigidbodyChildrenActiveStates.Clear();
for (int index = 0; index < rigidbodyChildren.Length; index++)
{
if (rigidbodyChildren[index].gameObject == JointContainer || rigidbodyChildren[index] == jointRigidbody)
{
rigidbodyChildrenActiveStates.Add(false);
continue;
}
rigidbodyChildrenActiveStates.Add(rigidbodyChildren[index].gameObject.activeSelf);
rigidbodyChildren[index].gameObject.SetActive(false);
}
// Set the current joint container to match the joint anchor to provide the correct offset.
JointContainer.transform.localPosition = Joint.anchor;
JointContainer.transform.localRotation = Quaternion.identity;
// Restore the state of child rigidbody GameObjects now the anchor position has been set.
for (int index = 0; index < rigidbodyChildren.Length; index++)
{
if (rigidbodyChildren[index].gameObject == JointContainer || rigidbodyChildren[index] == jointRigidbody)
{
continue;
}
rigidbodyChildren[index].gameObject.SetActive(rigidbodyChildrenActiveStates[index]);
}
}
}
}