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]); } } } }