wirm/Game/Assets/Scripts/DrawerDynamicJointConfiguration.cs

141 lines
5.4 KiB
C#
Raw Normal View History

using System;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit.Interactables;
[RequireComponent(typeof(XRGrabInteractable))]
[RequireComponent(typeof(ConfigurableJoint))]
public class DrawerDynamicJointConfiguration : MonoBehaviour
{
2025-02-01 12:27:08 +08:00
[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;
/// <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;
private void Awake()
{
// configure the configurable joint component
var cJoint = GetComponent<ConfigurableJoint>();
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<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
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
cJoint.anchor = jointAnchor;
Debug.Log($"Drawer (Dynamic): set to {jointAnchor}");
}
private enum MovementAxis
{
X,
Y,
Z
}
}