using System; using UnityEngine; using UnityEngine.XR.Interaction.Toolkit.Interactables; [RequireComponent(typeof(XRGrabInteractable))] [RequireComponent(typeof(ConfigurableJoint))] public class DrawerDynamicJointConfiguration : MonoBehaviour { [Header("mark's all-in-one dynamic drawer component")] [Space(10)] [HelpBox("make sure every child inside both prefabs are under the" + "'Interactable Environment' layer.\n\n" + "whatever non-standard (a la ProBuilder) object geometry under the " + "interactable prefab should have a convex mesh collider if the console nags about it!\n\n" + "any Curve Interaction Casters (a la 'XR Origin (VR)' > 'Camera Offset' > '... Controller' " + "> 'Near-Far Interactor' > 'Curve Interaction Caster') should be have the " + "'Interactable Environment' layer included in its' Raycast Mask.", HelpBoxMessageType.Error)] [Space(10)] [SerializeField] private MovementAxis movementAxis = MovementAxis.Z; /// /// the maximum distance the drawer can be pulled out /// [Tooltip("the maximum distance the drawer can be pulled out")] [SerializeField] private float maxMovementDistance = 0.5f; /// /// the velocity scale of the drawer, how fast it can move /// [Tooltip("the velocity scale of the drawer, how fast it can move")] [SerializeField] private float velocityScale = 0.5f; private void Awake() { // configure the configurable joint component var cJoint = GetComponent(); if (cJoint == null) throw new Exception("Drawer (Dynamic): ConfigurableJoint component not found (unreachable?)"); // lock all motions (linear and angular) except for the desired (linear) axis Debug.Log($"Drawer (Dynamic): locking movement to axis {movementAxis}"); cJoint.xMotion = movementAxis == MovementAxis.X ? ConfigurableJointMotion.Limited : ConfigurableJointMotion.Locked; cJoint.yMotion = movementAxis == MovementAxis.Y ? ConfigurableJointMotion.Limited : ConfigurableJointMotion.Locked; cJoint.zMotion = movementAxis == MovementAxis.Z ? ConfigurableJointMotion.Limited : ConfigurableJointMotion.Locked; cJoint.angularXMotion = ConfigurableJointMotion.Locked; cJoint.angularYMotion = ConfigurableJointMotion.Locked; cJoint.angularZMotion = ConfigurableJointMotion.Locked; // set linear limit cJoint.linearLimit = new SoftJointLimit { limit = maxMovementDistance, bounciness = 0, contactDistance = 0 }; // configure the rigidbody var rb = GetComponent(); rb.isKinematic = false; rb.useGravity = false; rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic; // configure the grab interactable var grabInteractable = GetComponent(); grabInteractable.movementType = XRBaseInteractable.MovementType.VelocityTracking; grabInteractable.trackPosition = true; grabInteractable.velocityScale = velocityScale; // guess the handle collider, lol Collider drawerDoorHandleCollider = GetComponentInChildren(); if (drawerDoorHandleCollider == null) { drawerDoorHandleCollider = GetComponentInChildren(); if (drawerDoorHandleCollider == null) { drawerDoorHandleCollider = GetComponentInChildren(); if (drawerDoorHandleCollider == null) { drawerDoorHandleCollider = GetComponentInChildren(); if (drawerDoorHandleCollider == null) throw new Exception("Drawer (Dynamic): Drawer door handle collider not found"); Debug.Log("Drawer (Dynamic): MeshCollider collider found"); } else { Debug.Log("Drawer (Dynamic): CapsuleCollider found"); } } else { Debug.Log("Drawer (Dynamic): SphereCollider found"); } } else { Debug.Log("Drawer (Dynamic): BoxCollider found"); } // set the joint's anchor to the handle's world position var handleWorldPosition = drawerDoorHandleCollider.transform.TransformPoint(drawerDoorHandleCollider.bounds.center); var jointAnchor = cJoint.transform.InverseTransformPoint(handleWorldPosition); switch (movementAxis) { case MovementAxis.X: jointAnchor.y = 0; jointAnchor.z = 0; break; case MovementAxis.Y: jointAnchor.x = 0; jointAnchor.z = 0; break; case MovementAxis.Z: jointAnchor.x = 0; jointAnchor.y = 0; break; default: jointAnchor = Vector3.zero; break; } cJoint.anchor = jointAnchor; Debug.Log($"Drawer (Dynamic): set to {jointAnchor}"); } private enum MovementAxis { X, Y, Z } }