118 lines
5.3 KiB
C#
118 lines
5.3 KiB
C#
// Copyright (C) 2014-2024 Gleechi Technology AB. All rights reserved.
|
|
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace VirtualGrasp.Onboarding
|
|
{
|
|
/**
|
|
* ManageContainerObject shows as a tutorial on how to use the VG_Controller.OnObjectFullyReleased
|
|
* and VG_Controller.OnObjectGrasped combined with Unity's physical joints to manage a
|
|
* container object to hold the contained physical objects stably without falling off.
|
|
*/
|
|
[LIBVIRTUALGRASP_UNITY_SCRIPT]
|
|
[HelpURL("https://docs.virtualgrasp.com/unity_vgonboarding_task3." + VG_Version.__VG_VERSION__ + ".html")]
|
|
public class ManageContainerObject : MonoBehaviour
|
|
{
|
|
/// A set off objects that are actively colliding with this one.
|
|
private HashSet<Transform> m_collisions = new HashSet<Transform>();
|
|
/// A map of objects with ArticulationBody to their original parents.
|
|
private Dictionary<Transform, Transform> m_parentCache = new Dictionary<Transform, Transform>();
|
|
/// A map of objects with Rigidbody to the fixed joints connecting to this container object
|
|
private Dictionary<Transform, FixedJoint> m_attachJoints = new Dictionary<Transform, FixedJoint>();
|
|
/// If dot product between velocity and down is large enough (ie. vectors are aligned).
|
|
public float m_dropAlignment = 0.8f;
|
|
|
|
private void Start()
|
|
{
|
|
// Register the some grasp event listeners
|
|
VG_Controller.OnObjectFullyReleased.AddListener(OnObjectFullyReleased);
|
|
VG_Controller.OnObjectGrasped.AddListener(OnObjectGrasped);
|
|
}
|
|
|
|
private void OnCollisionEnter(Collision collision)
|
|
{
|
|
// See if the object in collision is actually held by a hand (and is not a hand itself).
|
|
bool valid_object = true;
|
|
foreach (VG_HandStatus hand in VG_Controller.GetHands())
|
|
{
|
|
if (hand.m_hand == collision.transform)
|
|
valid_object &= false;
|
|
if (hand.m_selectedObject == collision.transform && hand.IsHolding())
|
|
valid_object &= false;
|
|
}
|
|
|
|
if (valid_object && // If it's valid ...
|
|
(collision.rigidbody != null || collision.gameObject.TryGetComponent(out ArticulationBody ab)) && // and has a rigid body or articulation body ...
|
|
Vector3.Dot(collision.relativeVelocity.normalized, Vector3.down) > m_dropAlignment) // .. and if the object is dropped from somewhat above.
|
|
{
|
|
Attach(collision.transform);
|
|
m_collisions.Add(collision.transform);
|
|
}
|
|
}
|
|
|
|
private void OnCollisionExit(Collision collision)
|
|
{
|
|
m_collisions.Remove(collision.transform);
|
|
}
|
|
|
|
private void OnObjectFullyReleased(VG_HandStatus hand)
|
|
{
|
|
if (m_collisions.Contains(hand.m_selectedObject))
|
|
Attach(hand.m_selectedObject);
|
|
}
|
|
|
|
private void OnObjectGrasped(VG_HandStatus hand)
|
|
{
|
|
Unattach(hand.m_selectedObject);
|
|
}
|
|
|
|
void Attach(Transform attachedObject)
|
|
{
|
|
if (attachedObject.gameObject.TryGetComponent<Rigidbody>(out Rigidbody rb))
|
|
{
|
|
if (!attachedObject.gameObject.TryGetComponent<FixedJoint>(out FixedJoint joint))
|
|
{
|
|
joint = attachedObject.gameObject.AddComponent<FixedJoint>();
|
|
m_attachJoints[attachedObject] = joint;
|
|
if (transform.gameObject.TryGetComponent<Rigidbody>(out Rigidbody container_rb))
|
|
joint.connectedBody = container_rb;
|
|
else if (transform.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody container_ab))
|
|
joint.connectedArticulationBody = container_ab;
|
|
}
|
|
}
|
|
else if (attachedObject.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody ab))
|
|
{
|
|
if (transform.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody container_ab))
|
|
{
|
|
m_parentCache[attachedObject] = attachedObject.parent;
|
|
attachedObject.SetParent(transform);
|
|
ab.jointType = ArticulationJointType.FixedJoint;
|
|
}
|
|
else
|
|
Debug.LogError("Can not attach object " + attachedObject.name + " with ArticulationBody to " + transform.name + " without ArticulationBody.");
|
|
}
|
|
}
|
|
|
|
void Unattach(Transform attachedObject)
|
|
{
|
|
if (attachedObject.gameObject.TryGetComponent<Rigidbody>(out Rigidbody rb))
|
|
{
|
|
if (!m_attachJoints.ContainsKey(attachedObject))
|
|
return;
|
|
DestroyImmediate(m_attachJoints[attachedObject]);
|
|
m_attachJoints.Remove(attachedObject);
|
|
}
|
|
else if (attachedObject.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody ab))
|
|
{
|
|
if (!transform.gameObject.TryGetComponent<ArticulationBody>(out ArticulationBody container_ab))
|
|
return;
|
|
if (attachedObject.parent != transform)
|
|
return;
|
|
|
|
attachedObject.SetParent(m_parentCache[attachedObject]);
|
|
}
|
|
}
|
|
}
|
|
}
|