2025-01-31 22:01:37 +08:00
|
|
|
using System;
|
|
|
|
using UnityEngine;
|
2025-02-09 20:24:02 +08:00
|
|
|
using UnityEngine.XR.Interaction.Toolkit.Interactables;
|
|
|
|
|
|
|
|
[RequireComponent(typeof(XRGrabInteractable))]
|
|
|
|
[RequireComponent(typeof(ConfigurableJoint))]
|
2025-01-31 22:01:37 +08:00
|
|
|
public class DrawerDynamicJointConfiguration : MonoBehaviour
|
|
|
|
{
|
2025-02-01 12:27:08 +08:00
|
|
|
[Header("mark's all-in-one dynamic drawer component")]
|
2025-01-31 22:01:37 +08:00
|
|
|
[Space(10)]
|
2025-02-01 03:16:41 +08:00
|
|
|
[HelpBox("make sure every child inside both prefabs are under the" +
|
|
|
|
"'Interactable Environment' layer.\n\n" +
|
2025-02-09 20:24:02 +08:00
|
|
|
"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)]
|
2025-01-31 22:01:37 +08:00
|
|
|
[Space(10)]
|
2025-02-01 03:16:41 +08:00
|
|
|
[SerializeField]
|
|
|
|
private MovementAxis movementAxis = MovementAxis.Z;
|
|
|
|
|
2025-02-09 20:24:02 +08:00
|
|
|
/// <summary>
|
|
|
|
/// the maximum distance the drawer can be pulled out
|
|
|
|
/// </summary>
|
|
|
|
[Tooltip("the maximum distance the drawer can be pulled out")] [SerializeField]
|
|
|
|
private float maxMovementDistance = 0.5f;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// the velocity scale of the drawer, how fast it can move
|
|
|
|
/// </summary>
|
|
|
|
[Tooltip("the velocity scale of the drawer, how fast it can move")] [SerializeField]
|
|
|
|
private float velocityScale = 0.5f;
|
2025-02-01 03:16:41 +08:00
|
|
|
|
2025-01-31 22:01:37 +08:00
|
|
|
private void Awake()
|
|
|
|
{
|
2025-02-09 20:24:02 +08:00
|
|
|
// configure the configurable joint component
|
2025-02-01 03:16:41 +08:00
|
|
|
var cJoint = GetComponent<ConfigurableJoint>();
|
|
|
|
if (cJoint == null)
|
2025-02-09 20:24:02 +08:00
|
|
|
throw new Exception("Drawer (Dynamic): ConfigurableJoint component not found (unreachable?)");
|
2025-02-01 03:16:41 +08:00
|
|
|
|
2025-02-09 20:24:02 +08:00
|
|
|
// 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;
|
2025-02-01 03:16:41 +08:00
|
|
|
cJoint.angularYMotion = ConfigurableJointMotion.Locked;
|
|
|
|
cJoint.angularZMotion = ConfigurableJointMotion.Locked;
|
|
|
|
|
2025-01-31 22:01:37 +08:00
|
|
|
// set linear limit
|
2025-02-01 03:16:41 +08:00
|
|
|
cJoint.linearLimit = new SoftJointLimit
|
2025-01-31 22:01:37 +08:00
|
|
|
{
|
2025-02-01 03:16:41 +08:00
|
|
|
limit = maxMovementDistance,
|
2025-01-31 22:01:37 +08:00
|
|
|
bounciness = 0,
|
|
|
|
contactDistance = 0
|
|
|
|
};
|
2025-02-09 20:24:02 +08:00
|
|
|
|
|
|
|
// configure the rigidbody
|
|
|
|
var rb = GetComponent<Rigidbody>();
|
|
|
|
rb.isKinematic = false;
|
|
|
|
rb.useGravity = false;
|
|
|
|
rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
|
|
|
|
|
|
|
|
// configure the grab interactable
|
|
|
|
var grabInteractable = GetComponent<XRGrabInteractable>();
|
|
|
|
grabInteractable.movementType = XRBaseInteractable.MovementType.VelocityTracking;
|
|
|
|
grabInteractable.trackPosition = true;
|
|
|
|
grabInteractable.velocityScale = velocityScale;
|
|
|
|
|
2025-02-01 12:27:08 +08:00
|
|
|
// guess the handle collider, lol
|
2025-02-01 03:16:41 +08:00
|
|
|
Collider drawerDoorHandleCollider = GetComponentInChildren<BoxCollider>();
|
|
|
|
if (drawerDoorHandleCollider == null)
|
|
|
|
{
|
|
|
|
drawerDoorHandleCollider = GetComponentInChildren<SphereCollider>();
|
|
|
|
if (drawerDoorHandleCollider == null)
|
|
|
|
{
|
|
|
|
drawerDoorHandleCollider = GetComponentInChildren<CapsuleCollider>();
|
|
|
|
if (drawerDoorHandleCollider == null)
|
|
|
|
{
|
|
|
|
drawerDoorHandleCollider = GetComponentInChildren<MeshCollider>();
|
|
|
|
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;
|
|
|
|
}
|
2025-02-01 12:27:08 +08:00
|
|
|
|
2025-02-01 03:16:41 +08:00
|
|
|
cJoint.anchor = jointAnchor;
|
|
|
|
Debug.Log($"Drawer (Dynamic): set to {jointAnchor}");
|
|
|
|
}
|
|
|
|
|
|
|
|
private enum MovementAxis
|
|
|
|
{
|
|
|
|
X,
|
|
|
|
Y,
|
|
|
|
Z
|
2025-01-31 22:01:37 +08:00
|
|
|
}
|
2025-02-01 03:16:41 +08:00
|
|
|
}
|