using System.Collections;
using UnityEngine;
namespace Passer {
/// Sockets can hold a Handles.
/// \image html SocketGizmo.png
/// \image rtf SocketGizmo.png
///
/// Attaching and Releasing
/// =======================
/// Attaching a Handle using Scripting
/// ---------------------------------
/// You can attach handles to the Socket GameObject by calling an Attach() function on the Socket.
/// This will try to attach the Transform, Rigidbody or Handle parameter to the Socket.
/// On the other hand you can release Handles again by calling an Release() function on the Socket.
/// This will release the currently attached Handle from the Socket.
///
/// Attaching a Prefab with a Handle in the Editor
/// -----------------------------------------------
/// It is possible to attach a Handle prefab to a socket in the Unity editor.
/// In this way the socket will start with a Handle attached.
/// This is done by assigning a Prefab to the Attached Prefab field of the Socket.
/// This will automatically create an instance of the prefab which is attached to the socket.
/// When the Attached Prefab field is cleared again,
/// the prefab instance attached to the socket is released and destroyed again.
///
/// Releasing a Handle to another Socket
/// ------------------------------------
/// When an handle is attached to a socket and the Handle is attached to another socket
/// it will be automatically released from the original socket.
///
/// Socket Tag
/// ==========
/// With the Socket Tag field to is possible to limit the Handles
/// which can attach to this socket to those who have the right Tag.
/// This construction is using the standard
/// Unity tags.
///
/// Events
/// ======
/// * \ref Socket::attachEvent "Attach Events"
///
/// Attachment Implementation
/// =========================
/// Depending on the type of socket and its GameObject handles are attached to sockets in various ways.
///
/// A Static Socket...
/// -------------------
/// ...with a Non-Kinematic Rigidbody Handle
/// -----------------------------------------
/// A non-kinematic Rigidbody will get a Joint which limits its movement to
/// the location and orientation of the Socket. This joint is implemented using a Configurable Joint.
/// When the Handle is released, the joint is destroyed again.
///
/// ...with a Kinematic Rigidbody Handle
/// --------------------------------------
/// A kinematic Rigidbody with an handle will the parented to the static Socket Transform.
/// The result will be that the Transform of the Rigidbody is a child of the Socket Transform.
/// The Rigidbody will be temporarily removed.The settings will be conserved
/// in a RigidbodyDisabled Component which is used to restore the Rigidbody when the Handle
/// is released from the Socket.
///
/// ...with a Static Handle
/// ------------------------
/// Static Handles cannot be attached to static Sockets.
/// This will lead to a warning message in the Console: “Cannot attach static handle to static socket”.
///
/// A Kinematic Rigidbody Socket...
/// -------------------------------
/// ...with a Non-Kinematic Rigidbody Handle
/// -----------------------------------------
/// If the Non-Kinematic Rigidbody Handle has one or more Joints or when it has constraints set,
/// it will be attached to the Socket using a Joint.
/// This joint is implemented using a Configurable Joint.
/// When the Handle is released, the joint is destroyed again.
/// In all other case, the non-kinematic Rigidbody will the parented to
/// the kinematic Rigidbody Socket Transform.
/// The result will be that the Transform of the Rigidbody is a child of the Socket Transform.
/// The Rigidbody will be temporarily removed.
/// The settings will be conserved in a RigidbodyDisabled Component
/// which is used to restore the Rigidbody when the Handle is released from the Socket.
///
/// ...with a Kinematic Rigidbody Handle
/// -------------------------------------
/// A kinematic Rigidbody with an handle will the parented to the kinematic Rigidbody Socket Transform.
/// The result will be that the Transform of the Rigidbody is a child of the Socket Transform.
///
/// ...with a Static Handle
/// ------------------------
/// In this case, the kinematic Rigidbody Socket is parented to the static Handle Transform.
/// The result will be that the Transform of the Scoket is a child of the Handle Transform.
/// The Rigidbody of the Socket will be temporarily removed.
/// The settings will be conserved in a RigidbodyDisabled Component
/// which is used to restore the Rigidbody when the Handle is released from the Socket.
///
/// A Non-Kinematic Rigidbody Socket...
/// -----------------------------------
/// ...with a Non-Kinematic Rigidbody Handle
/// ----------------------------------------
/// If the Non-Kinematic Rigidbody Handle has one or more Joints or when it has constraints set,
/// it will be attached to the Socket using a Joint.
/// This joint is implemented using a Configurable Joint.
/// When the Handle is released, the joint is destroyed again.
/// In all other cases, the non-kinematic Rigidbody will the parented to
/// the kinematic Rigidbody Socket Transform.
/// The result will be that the Transform of the Rigidbody is a child of the Socket Transform.
/// The Rigidbody will be temporarily removed.
/// The settings will be conserved in a RigidbodyDisabled Component
/// which is used to restore the Rigidbody when the Handle is released from the Socket.
///
/// ...with a Kinematic Rigidbody Handle
/// ------------------------------------
/// A kinematic Rigidbody with an handle will the parented to the non-kinematic Socket Transform.
/// The result will be that the Transform of the Rigidbody is a child of the Socket Transform.
/// The Rigidbody will be temporarily removed.
/// The settings will be conserved in a RigidbodyDisabled Component
/// which is used to restore the Rigidbody when the Handle is released from the Socket.
///
/// ...with a Static Handle
/// -----------------------
/// In this case, the socket Rigidbody will be attached to the Handle using a Joint.
/// This joint is implemented using a Configurable Joint
/// such that it will follow the Handle’s Transform as closely as possible.
/// When the Handle is released, the joint is destroyed again.
[HelpURL("https://passervr.com/apis/HumanoidControl/Unity/class_passer_1_1_socket.html")]
public class Socket : MonoBehaviour {
protected static void DebugLog(string s) {
//Debug.Log(s);
}
///
/// Does the socket currently have a handle attached?
///
public bool isOccupied {
get {
return this.attachedTransform != null;
}
}
///
/// A prefab which is used to attach to the socket at startup.
///
public GameObject attachedPrefab;
/// The Transform attached to this socket
/// If the socket holds a Handle, this will contain the Transform of the Handle.
/// It will be null otherwise
public Transform attachedTransform;
protected Transform releasingTransform;
public Handle attachedHandle;
/// The parent of the attached transform before it was attached
/// This is used to restore the parent when the transform is released again.
protected Transform attachedTransformParent;
/// A tag for limiting which handles can be held by the socket
/// If set (not null or empty) only Handles with the given tag will fit in the socket.
public string socketTag;
public enum AttachMethod {
Unknown,
Parenting,
ReverseParenting,
Joint,
StaticJoint,
ColliderDuplication
}
public AttachMethod attachMethod = AttachMethod.Unknown;
protected RigidbodyDisabled rigidbodyDisabled = null;
public bool destroyOnLoad = false;
#region Alignment
protected virtual void MoveHandleToSocket(Transform socketTransform, Rigidbody handleRigidbody, Handle handle) {
DebugLog("MoveHandleToSocket");
Transform handleTransform = handle.GetComponent();
if (handleRigidbody != null)
handleTransform = handleRigidbody.transform;
if (handle.grabType == Handle.GrabType.RailGrab) {
MoveRailToSocket(socketTransform, handleTransform, handle);
}
else {
handleTransform.rotation = handle.RotationTo(socketTransform.rotation) * handleTransform.rotation;
handleTransform.position += handle.TranslationTo(socketTransform.position);
}
}
protected virtual void MoveRailToSocket(Transform socketTransform, Transform railTransform, Handle rail) {
Vector3 handleYaxis = rail.transform.up;
Vector3 socketYaxis = socketTransform.up;
float angle = Vector3.Angle(handleYaxis, socketYaxis);
if (angle > 90)
socketYaxis = -socketTransform.up;
Quaternion socketToHandleRotation = Quaternion.FromToRotation(socketYaxis, handleYaxis);
Quaternion targetRotation = Quaternion.Inverse(socketToHandleRotation) * railTransform.rotation;
railTransform.rotation = rail.RotationTo(targetRotation) * railTransform.rotation;
// Socket along rail
Vector3 localSocketPosition = socketTransform.position - rail.transform.position;
Vector3 positionOnRail = Vector3.Project(localSocketPosition, rail.transform.up);
Vector3 railToSocket = localSocketPosition - positionOnRail;
// Socket within rail length
float maxDistance = rail.transform.lossyScale.y / 2;
float distance = positionOnRail.magnitude - maxDistance;
if (distance > 0) {
float scale = distance / positionOnRail.magnitude;
railToSocket += Vector3.Scale(positionOnRail, Vector3.one * scale);
}
railTransform.position += railToSocket;
}
protected virtual void MoveHandleToSocket(Transform socketTransform, Handle handle) {
DebugLog("MoveHandleToSocket");
Transform handleTransform = handle.GetComponent();
Rigidbody handleRigidbody = handle.GetComponentInParent();
if (handleRigidbody != null) {
handleTransform = handleRigidbody.transform;
MechanicalJoint handleLimitations = handle.GetComponent();
if (handleRigidbody.isKinematic && handleLimitations != null && handleLimitations.enabled) {
//handleTransform.position += handle.TranslationTo(socketTransform.position);
// No rotations for kinematic Limitations
return;
}
}
if (handle.grabType == Handle.GrabType.RailGrab) {
MoveRailToSocket(socketTransform, handleTransform, handle);
}
else {
handleTransform.rotation = handle.RotationTo(socketTransform.rotation) * handleTransform.rotation;
handleTransform.position += handle.TranslationTo(socketTransform.position);
}
}
protected virtual void MoveSocketToHandle(Transform socketTransform, Handle handle) {
DebugLog("MoveSocketToHandle");
socketTransform.rotation *= Quaternion.Inverse(handle.RotationTo(socketTransform.rotation));
socketTransform.position -= handle.TranslationTo(socketTransform.position);
}
protected virtual void MoveSocketToHandle(Transform socketTransform, Rigidbody socketRigidbody, Handle handle) {
DebugLog("MoveSocketToHandle");
//Quaternion rotation = Quaternion.Inverse(handle.RotationTo(socketTransform.rotation));
//socketRigidbody.transform.rotation *= rotation;
//Vector3 translation = handle.TranslationTo(socketTransform.position);
//socketRigidbody.transform.position -= translation;
// code based on HandSocket, potentially better, but rotation is somehow wrong
Quaternion socket2rigidbodyRotation = Quaternion.Inverse(socketTransform.localRotation);
socketRigidbody.transform.rotation = handle.transform.rotation * socket2rigidbodyRotation;
Vector3 socket2RigidbodyPosition = socketRigidbody.transform.position - socketTransform.position;
socketRigidbody.transform.position = handle.transform.position + socket2RigidbodyPosition;
}
#endregion Alignment
#region Attach
public void Attach(GameObject objectToAttach) {
Attach(objectToAttach, false);
}
public bool Attach(GameObject objectToAttach, bool rangeCheck) {
bool success = Attach(objectToAttach.transform, rangeCheck);
return success;
}
/// Tries to attach the given Transform to this socket
/// If the Transform has a Handle with the right Socket Tag it will be attached to the socket.
/// Static and Kinematic Rigidbodies will be attached by parenting.
/// Non-Kinematic Rigidbodies will be attached using a joint.
/// The Transform to attach to this socket
/// Boolean indicating whether attachment succeeded
public virtual bool Attach(Transform transformToAttach, bool rangeCheck = true) {
DebugLog("Attach transform " + transformToAttach);
Handle handle;
Rigidbody rigidbodyToAttach = transformToAttach.GetComponentInParent();
if (rigidbodyToAttach != null)
handle = rigidbodyToAttach.GetComponentInChildren();
else
handle = transformToAttach.GetComponentInChildren();
if (handle == null) {
// Transform does not have a handle
DebugLog(gameObject.name + ": Attach failed. Object " + transformToAttach.name + " does not have a handle");
return false;
}
if (handle.socket != null) {
// Handle is already in a socket
return false;
}
if (socketTag != null && socketTag != "" && !transformToAttach.gameObject.CompareTag(socketTag)) {
// Object did not have the right tag
Debug.Log(gameObject.name + ": Attach failed. Object " + transformToAttach + " does not have the right tag"); ;
return false;
}
Rigidbody handleRigidbody = handle.GetComponentInParent();
if (handleRigidbody != rigidbodyToAttach) {
// Object does not have a handle,
// found handle is of child rigidbody
//Debug.Log(gameObject.name + ": Attach failed. Object does not have a handle. Handle is on child Rigidbody.");
return false;
}
bool success = Attach(handle, rangeCheck);
return success;
}
/// Tries to attach the given Transform to this socket
/// If the Handle has the right Socket Tag it will be attached to the socket.
/// Static and Kinematic Rigidbodies will be attached by parenting.
/// Non-Kinematic Rigidbodies will be attached using a joint.
/// The Handle to attach to this socket
/// Boolean indicating whether attachment succeeded
public virtual bool Attach(Handle handle, bool rangeCheck = true) {
DebugLog(this.gameObject.name + " Attach handle " + handle);
if (handle == null) {
// Transform does not have a handle
DebugLog(gameObject.name + ": Attach failed. Transform does not have a handle");
return false;
}
if (handle.socket != null) {
// Handle is already in a socket
return false;
}
if (socketTag != null && socketTag != "" && !handle.gameObject.CompareTag(socketTag)) {
// Object did not have the right tag
Debug.Log(gameObject.name + ": Attach failed. Handle " + handle + " does not have the right tag"); ;
return false;
}
Rigidbody rigidbodyToAttach = handle.GetComponentInParent();
if (rigidbodyToAttach == null)
return AttachStaticObject(handle.transform, handle);
else {
RigidbodyDisabled disabledRigidbody = RigidbodyDisabled.Get(rigidbodyToAttach.transform);
if (disabledRigidbody != null && rigidbodyToAttach.transform.parent != null)
rigidbodyToAttach = rigidbodyToAttach.transform.parent.GetComponentInParent();
if (rigidbodyToAttach == null)
return AttachStaticObject(handle.transform, handle);
else
return AttachRigidbody(rigidbodyToAttach, handle, rangeCheck);
}
}
#region Rigidbody
protected virtual bool AttachRigidbody(Rigidbody objRigidbody, Handle handle, bool rangeCheck = true) {
DebugLog("AttachRigidbody " + objRigidbody);
float grabDistance = Vector3.Distance(this.transform.position, handle.transform.position);
if (rangeCheck && handle.range > 0 && grabDistance > handle.range) {
//Debug.Log("Socket is outside range of handle");
return false;
}
Transform objTransform = objRigidbody.transform;
Rigidbody thisRigidbody = this.GetComponentInParent();
Joint joint = objRigidbody.GetComponent();
// See if these joints are being destroyed
DestroyedJoints destroyedJoints = objRigidbody.GetComponent();
if (objRigidbody.isKinematic) {
if (thisRigidbody == null)
AttachRigidbodyParenting(objRigidbody, handle);
else if (thisRigidbody.isKinematic)
AttachTransformParenting(objRigidbody.transform, handle);
else
AttachSocketParenting(objRigidbody, handle, thisRigidbody);
}
else if (thisRigidbody == null) {
AttachRigidbodyReverseJoint(objRigidbody, handle);
}
else if (
(joint != null && destroyedJoints == null) ||
objRigidbody.constraints != RigidbodyConstraints.None
) {
//|| otherHandPhysics != null) {
AttachRigidbodyJoint(objRigidbody, handle);
}
else {
AttachRigidbodyParenting(objRigidbody, handle);
}
releasingTransform = null;
attachedTransform = objTransform;
handle.socket = this;
return true;
}
protected void AttachTransformParenting(Transform objTransform, Handle handle) {
Debug.Log("AttachTransformParenting: " + objTransform);
attachedTransformParent = objTransform.parent;
Rigidbody handleRigidbody = handle.GetComponentInParent();
MechanicalJoint handleLimitations = handleRigidbody.GetComponent();
if (handleRigidbody.isKinematic && handleLimitations != null && handleLimitations.enabled) {
MoveSocketToHandle(this.transform, handle);
}
else
MoveHandleToSocket(this.transform, handle);
objTransform.SetParent(this.transform);
attachedTransform = objTransform;
attachedHandle = handle;
handle.socket = this;
}
protected virtual void AttachRigidbodyParenting(Rigidbody objRigidbody, Handle handle) {
DebugLog("AttachRigidbodyParenting");
MoveHandleToSocket(this.transform, objRigidbody, handle);
attachedTransform = objRigidbody.transform;
Rigidbody thisRigidbody = this.GetComponentInParent();
if (thisRigidbody != null)
MassRedistribution(thisRigidbody, objRigidbody);
RigidbodyDisabled.ParentRigidbody(this.transform, objRigidbody);
Humanoid.HumanoidNetworking.DisableNetworkSync(attachedTransform.gameObject);
attachedHandle = handle;
handle.socket = this;
}
protected virtual void AttachRigidbodyJoint(Rigidbody objRigidbody, Handle handle) {
DebugLog("AttachRigidbodyJoint " + objRigidbody);
//MassRedistribution(thisRididbody, objRigidbody);
MoveHandleToSocket(this.transform, handle);
ConfigurableJoint joint = this.gameObject.AddComponent();
joint.xMotion = ConfigurableJointMotion.Locked;
joint.yMotion = ConfigurableJointMotion.Locked;
joint.zMotion = ConfigurableJointMotion.Locked;
joint.angularXMotion = ConfigurableJointMotion.Locked;
joint.angularYMotion = ConfigurableJointMotion.Locked;
joint.angularZMotion = ConfigurableJointMotion.Locked;
joint.projectionMode = JointProjectionMode.PositionAndRotation;
joint.projectionDistance = 0.01F;
joint.projectionAngle = 1;
Collider c = objRigidbody.transform.GetComponentInChildren();
joint.connectedBody = c.attachedRigidbody;
attachedTransform = objRigidbody.transform;
attachedHandle = handle;
handle.socket = this;
}
/// Attach handle to socket using a static joint on the handle
protected virtual void AttachRigidbodyReverseJoint(Rigidbody objRigidbody, Handle handle) {
DebugLog("AttachRigidbodyReverseJoint " + objRigidbody);
MoveHandleToSocket(this.transform, handle);
ConfigurableJoint joint = objRigidbody.gameObject.AddComponent();
joint.xMotion = ConfigurableJointMotion.Locked;
joint.yMotion = ConfigurableJointMotion.Locked;
joint.zMotion = ConfigurableJointMotion.Locked;
joint.angularXMotion = ConfigurableJointMotion.Locked;
joint.angularYMotion = ConfigurableJointMotion.Locked;
joint.angularZMotion = ConfigurableJointMotion.Locked;
joint.projectionMode = JointProjectionMode.PositionAndRotation;
joint.projectionDistance = 0.01F;
joint.projectionAngle = 1;
joint.breakForce = float.PositiveInfinity;
joint.breakTorque = float.PositiveInfinity;
attachedTransform = objRigidbody.transform;
attachedHandle = handle;
handle.socket = this;
}
protected virtual void AttachSocketParenting(Rigidbody objRigidbody, Handle handle, Rigidbody socketRigidbody) {
DebugLog("AttachSocketParenting");
RigidbodyDisabled.ParentRigidbody(objRigidbody, socketRigidbody);
MoveSocketToHandle(this.transform, handle);
attachedTransform = objRigidbody.transform;
attachedHandle = handle;
handle.socket = this;
attachMethod = AttachMethod.ReverseParenting;
}
protected float originalMass = 1;
protected bool originalUseGravity = false;
protected virtual void MassRedistribution(Rigidbody socketRigidbody, Rigidbody objRigidbody) {
originalMass = socketRigidbody.mass;
socketRigidbody.mass = HybridPhysics.CalculateTotalMass(objRigidbody);
originalUseGravity = socketRigidbody.useGravity;
// This gives an issue when attaching things to a socket which is already in the hand
// It will enable gravity on the hand in that case (not on the object in the hand)
// Which gives less stable hand tracking.
// Update: added additional check such that gravity is only enabled when
// holding heavy objects
if (objRigidbody.useGravity && objRigidbody.mass > HybridPhysics.kinematicMass)
socketRigidbody.useGravity = true;
}
#endregion Rigidbody
#region Static Object
virtual protected bool AttachStaticObject(Transform objTransform, Handle handle) {
DebugLog("AttachStaticObject " + objTransform);
Rigidbody thisRigidbody = this.GetComponentInParent();
if (thisRigidbody == null) {
Debug.LogWarning("Cannot attach static handle to static socket");
return false;
}
// To do: rangecheck
if (thisRigidbody.isKinematic) {
AttachSocketParenting(objTransform, handle, thisRigidbody);
}
else {
MoveSocketToHandle(this.transform, handle);
if (handle.grabType == Handle.GrabType.RailGrab)
AttachStaticJointRotY(objTransform);
else
AttachStaticJoint(objTransform);
}
releasingTransform = null;
attachedTransform = objTransform;
attachedHandle = handle;
handle.socket = this;
return true;
}
protected virtual void AttachSocketParenting(Transform objTransform, Handle handle, Rigidbody thisRigidbody) {
DebugLog("AttachSocketParenting");
RigidbodyDisabled.ParentRigidbody(objTransform, thisRigidbody);
MoveSocketToHandle(this.transform, handle);
}
public virtual void AttachStaticJoint(Transform objTransform) {
DebugLog("AttachStaticJoint");
FixedJoint joint = this.transform.gameObject.AddComponent();
Collider c = objTransform.GetComponentInChildren();
if (c == null)
c = objTransform.GetComponentInParent();
joint.connectedBody = c.attachedRigidbody;
}
virtual protected void AttachStaticJointRotY(Transform objTransform) {
DebugLog("AttachStaticJointRotY is still fixed");
FixedJoint joint = this.transform.gameObject.AddComponent();
Collider c = objTransform.GetComponentInChildren();
if (c == null)
c = objTransform.GetComponentInParent();
joint.connectedBody = c.attachedRigidbody;
}
#endregion Static Object
#endregion Attach
#region Release
/// Releases a Transform from the socket
/// Note that if the Transform is not taken out of the range of the socket
/// or held by another Socket, it will automatically snap back to the Socket.
public virtual void Release(bool releaseSticky = false) {
DebugLog("Release " + attachedTransform);
if (attachedTransform == null) {
attachedHandle = null;
return;
}
if (attachedHandle != null && attachedHandle.sticky && !releaseSticky)
return;
Rigidbody thisRigidbody = this.GetComponentInParent();
Rigidbody objRigidbody = attachedTransform.GetComponentInParent();
RigidbodyDisabled objRigidbodyDisabled = RigidbodyDisabled.Get(attachedTransform);
// RigidbodyDisabled.GetInParent does not work well here.
// When a socket is held in another socket, it can find the disabledRigidbody of the other socket
//RigidbodyDisabled thisRigidbodyDisabled = RigidbodyDisabled.Get(this.transform);
switch (attachMethod) {
case AttachMethod.ReverseParenting:
if (this.rigidbodyDisabled != null)
ReleaseSocketParenting(objRigidbody, this.rigidbodyDisabled.transform);
else if (thisRigidbody != null)
ReleaseSocketParenting(objRigidbody, this.transform);
else {
Debug.LogError("Release ReverseParenting without a (distroyed) rigidbody present");
return;
}
break;
default:
if (this.rigidbodyDisabled != null)
ReleaseSocketParenting(objRigidbody, this.rigidbodyDisabled.transform);
else if (objRigidbodyDisabled != null)
ReleaseRigidbodyParenting();
else if (objRigidbody == null)
ReleaseStaticObject();
else if (thisRigidbody != null && thisRigidbody.isKinematic)
ReleaseTransformParenting();
else if (!objRigidbody.isKinematic && thisRigidbody == null)
ReleaseRigidbodyReverseJoint();
else
ReleaseRigidbodyJoint();
break;
}
Handle handle = attachedHandle; // attachedTransform.GetComponentInChildren();
if (handle != null) {
handle.socket = null;
}
this.releasingTransform = this.attachedTransform;
this.attachedTransform = null;
this.attachedHandle = null;
attachMethod = AttachMethod.Unknown;
StartCoroutine(ClearReleasingTransform());
}
// Released objects should be gone within 1 second or they will be reattached
private IEnumerator ClearReleasingTransform() {
yield return new WaitForSeconds(1);
this.releasingTransform = null;
}
#region Rigidbody
protected virtual void ReleaseRigidbodyParenting() {
DebugLog("Release Rigidbody from Parenting");
Rigidbody thisRigidbody = this.GetComponentInParent();
Rigidbody objRigidbody;
if (thisRigidbody == null)
objRigidbody = RigidbodyDisabled.UnparentRigidbody(this.transform, attachedTransform);
else
objRigidbody = RigidbodyDisabled.UnparentRigidbody(thisRigidbody, attachedTransform);
MassRestoration(thisRigidbody, objRigidbody);
Humanoid.HumanoidNetworking.ReenableNetworkSync(objRigidbody.gameObject);
if (thisRigidbody != null) {
objRigidbody.velocity = thisRigidbody.velocity;
objRigidbody.angularVelocity = thisRigidbody.angularVelocity;
}
// check if the object is released from an hybrid physics rigidbody (just hands for now)
Humanoid.AdvancedHandPhysics handPhysics = this.transform.GetComponentInParent();
if (handPhysics != null) {
Collider[] objColliders = objRigidbody.GetComponentsInChildren();
foreach (Collider objCollider in objColliders)
Target.UnsetColliderToTrigger(handPhysics.handTarget.colliders, objCollider);
}
}
protected virtual void ReleaseRigidbodyJoint() {
DebugLog("Release from Joint");
Joint[] joints = this.gameObject.GetComponents();
foreach (Joint joint in joints) {
#if UNITY_EDITOR
if (!Application.isPlaying)
DestroyImmediate(joint, true);
else
#endif
Destroy(joint);
}
//MassRestoration(..., ...);
// Trick: when released and immediately attached to anther socket (e.g. grabbing)
// the joints are not yet destroyed, because Destroy is executed with a delay.
// Adding the DestroyedJoints component indicates that the joints which may
// still be there are to be destroyed.
attachedTransform.gameObject.AddComponent();
}
protected void ReleaseRigidbodyReverseJoint() {
DebugLog("Release from reverse Joint");
Joint[] joints = attachedTransform.GetComponents();
foreach (Joint joint in joints) {
#if UNITY_EDITOR
if (!Application.isPlaying)
DestroyImmediate(joint, true);
else
#endif
Destroy(joint);
}
//MassRestoration(..., ...);
// Trick: when released and immediately attached to anther socket (e.g. grabbing)
// the joints are not yet destroyed, because Destroy is executed with a delay.
// Adding the DestroyedJoints component indicates that the joints which may
// still be there are to be destroyed.
attachedTransform.gameObject.AddComponent();
}
protected virtual void ReleaseSocketParenting(Rigidbody objRigidbody, Transform socketTransform) {
DebugLog("ReleaseSocketParenting");
RigidbodyDisabled.UnparentRigidbody(objRigidbody, socketTransform);
}
protected virtual void MassRestoration(Rigidbody socketRigidbody, Rigidbody objRigidbody) {
if (socketRigidbody != null) {
socketRigidbody.mass = originalMass;
socketRigidbody.useGravity = originalUseGravity;
}
}
#endregion Rigidbody
#region Static Object
protected virtual void ReleaseStaticObject() {
DebugLog("ReleaseStaticObject");
Rigidbody thisRigidbody = this.GetComponent();
RigidbodyDisabled thisDisabledRigidbody = RigidbodyDisabled.Get(this.transform);
if (thisRigidbody != null)
ReleaseStaticJoint();
else if (thisDisabledRigidbody != null)
ReleaseSocketParenting(attachedTransform);
else
ReleaseTransformParenting();
}
public virtual void ReleaseStaticJoint() {
DebugLog("ReleaseStaticJoint");
Joint[] joints = this.GetComponents();
foreach (Joint joint in joints) {
#if UNITY_EDITOR
if (!Application.isPlaying)
DestroyImmediate(joint, true);
else
#endif
Destroy(joint);
}
}
protected void ReleaseTransformParenting() {
DebugLog("Release Transform from Parenting");
attachedTransform.SetParent(attachedTransformParent);
}
protected void ReleaseSocketParenting(Transform objTransform) {
DebugLog("ReleaseSocketParenting");
RigidbodyDisabled.UnparentRigidbody(objTransform, this.transform);
}
#endregion Static Object
#endregion Release
#region Start
protected virtual void Awake() {
UnityEngine.SceneManagement.SceneManager.sceneUnloaded += OnSceneUnload;
}
#endregion Start
#region Update
protected virtual void Update() {
UpdateHolding();
}
#endregion
#region Events
protected static string[] attachEventTypeLabels = {
"Never",
"On Attach",
"On Release",
"While Attached",
"While Released",
"When Changed",
"Always"
};
/// A GameObject Event for triggering changes in the Transform held by the Socket
public GameObjectEventHandlers attachEvent = new GameObjectEventHandlers() {
label = "Hold Event",
tooltip =
"Call functions using what the socket is holding\n" +
"Parameter: the GameObject held by the socket",
eventTypeLabels = attachEventTypeLabels
};
protected void UpdateHolding() {
if (attachedTransform != null)
attachEvent.value = attachedTransform.gameObject;
else
attachEvent.value = null;
}
protected virtual void OnSceneUnload(UnityEngine.SceneManagement.Scene _) {
if (destroyOnLoad) {
if (attachedTransform != null) {
Destroy(attachedTransform.gameObject);
}
}
}
#endregion
#region Gizmos
protected Mesh gizmoMesh;
public void OnDrawGizmosSelected() {
if (gizmoMesh == null)
gizmoMesh = GenerateGizmoMesh1();
Gizmos.color = Color.yellow;
Gizmos.DrawWireMesh(gizmoMesh, transform.position, transform.rotation);
}
public static Mesh GenerateGizmoMesh1() {
Vector3 p0 = new Vector3(-0.01F, 0.03F, -0.01F);
Vector3 p1 = new Vector3(-0.01F, -0.03F, -0.01F);
Vector3 p2 = new Vector3(-0.01F, -0.03F, 0.01F);
Vector3 p3 = new Vector3(-0.01F, 0.01F, 0.01F);
Vector3 p4 = new Vector3(-0.01F, 0.01F, 0.03F);
Vector3 p5 = new Vector3(-0.01F, 0.03F, 0.03F);
Vector3 p6 = new Vector3(0.01F, 0.03F, -0.01F);
Vector3 p7 = new Vector3(0.01F, -0.03F, -0.01F);
Vector3 p8 = new Vector3(0.01F, -0.03F, 0.01F);
Vector3 p9 = new Vector3(0.01F, 0.01F, 0.01F);
Vector3 p10 = new Vector3(0.01F, 0.01F, 0.03F);
Vector3 p11 = new Vector3(0.01F, 0.03F, 0.03F);
Vector3[] vertices = {
p0, p1, p6, p7, // 0, 1, 2, 3
p1, p2, p7, p8, // 4, 5, 6, 7
p2, p3, p8, p9, // 8, 9, 10, 11
p3, p4, p9, p10, // 12, 13, 14, 15
p4, p5, p10, p11, // 16, 17, 18, 19
p5, p0, p11, p6, // 20, 21, 22, 23
//p0, p1, p2, p3, p4, p5, // 24, 25, 26, 27, 28, 29
//p6, p7, p8, p9, p10, p11, // 30, 31, 32, 33, 34, 35
};
int[] triangles = {
0, 2, 2, 3, 1, 1, 0, 1, 1, 3, 2, 2,
4, 6, 6, 7, 5, 5, 4, 5, 5, 7, 6, 6,
8, 10, 10, 11, 9, 9, 8, 9, 9, 11, 10, 10,
12, 14, 14, 15, 13, 13, 12, 13, 13, 15, 14, 14,
16, 18, 18, 19, 17, 17, 16, 17, 17, 19, 18, 18,
20, 22, 22, 23, 21, 21, 20, 21, 21, 23, 22, 22,
};
Vector3[] normals = {
Vector3.back, Vector3.back, Vector3.back, Vector3.back, //back
Vector3.down, Vector3.down, Vector3.down, Vector3.down, //down
Vector3.forward, Vector3.forward, Vector3.forward, Vector3.forward, //forward
Vector3.down, Vector3.down, Vector3.down, Vector3.down, //down
Vector3.forward, Vector3.forward, Vector3.forward, Vector3.forward, //forward
Vector3.up, Vector3.up, Vector3.up, Vector3.up, //up
//Vector3.left, Vector3.left, Vector3.left, Vector3.left, Vector3.left, Vector3.left,
//Vector3.right, Vector3.right, Vector3.right, Vector3.right, Vector3.right, Vector3.right,
};
Mesh gizmoMesh = new Mesh() {
vertices = vertices,
triangles = triangles,
normals = normals
};
return gizmoMesh;
}
public static Mesh GenerateGizmoMesh() {
Vector3 p0 = new Vector3(-0.01F, 0.03F, -0.01F);
Vector3 p1 = new Vector3(-0.01F, -0.03F, -0.01F);
Vector3 p2 = new Vector3(-0.01F, -0.03F, 0.01F);
Vector3 p3 = new Vector3(-0.01F, 0.01F, 0.01F);
Vector3 p4 = new Vector3(-0.01F, 0.01F, 0.03F);
Vector3 p5 = new Vector3(-0.01F, 0.03F, 0.03F);
Vector3 p6 = new Vector3(0.01F, 0.03F, -0.01F);
Vector3 p7 = new Vector3(0.01F, -0.03F, -0.01F);
Vector3 p8 = new Vector3(0.01F, -0.03F, 0.01F);
Vector3 p9 = new Vector3(0.01F, 0.01F, 0.01F);
Vector3 p10 = new Vector3(0.01F, 0.01F, 0.03F);
Vector3 p11 = new Vector3(0.01F, 0.03F, 0.03F);
Vector3[] vertices = {
p0, p1, p6, p7, // 0, 1, 2, 3
p1, p2, p7, p8, // 4, 5, 6, 7
p2, p3, p8, p9, // 8, 9, 10, 11
p3, p4, p9, p10, // 12, 13, 14, 15
p4, p5, p10, p11, // 16, 17, 18, 19
p5, p0, p11, p6, // 20, 21, 22, 23
p0, p1, p2, p3, p4, p5, // 24, 25, 26, 27, 28, 29
p6, p7, p8, p9, p10, p11, // 30, 31, 32, 33, 34, 35
};
int[] triangles = {
0, 2, 1, 3, 1, 2,
4, 6, 5, 7, 5, 6,
8, 10, 9, 11, 9, 10,
12, 14, 13, 15, 13, 14,
16, 18, 17, 19, 17, 18,
20, 22, 21, 23, 21, 22,
27,24,25, 27,25,26, 29,27,28, 27,29,24,
30,33,31, 31,33,32, 33,35,34, 35,33,30,
};
Vector3[] normals = {
Vector3.back, Vector3.back, Vector3.back, Vector3.back, //back
Vector3.down, Vector3.down, Vector3.down, Vector3.down, //down
Vector3.forward, Vector3.forward, Vector3.forward, Vector3.forward, //forward
Vector3.down, Vector3.down, Vector3.down, Vector3.down, //down
Vector3.forward, Vector3.forward, Vector3.forward, Vector3.forward, //forward
Vector3.up, Vector3.up, Vector3.up, Vector3.up, //up
Vector3.left, Vector3.left, Vector3.left, Vector3.left, Vector3.left, Vector3.left,
Vector3.right, Vector3.right, Vector3.right, Vector3.right, Vector3.right, Vector3.right,
};
Mesh gizmoMesh = new Mesh() {
vertices = vertices,
triangles = triangles,
normals = normals
};
return gizmoMesh;
}
#endregion
}
// Component to indicate that the joints are being destroyed
// When a rigidbody is released and immediately attached to anther socket (e.g. grabbing)
// the joints may not yet be destroyed when they are grabbed, because Destroy is executed with a delay.
// Adding the DestroyedJoints component indicates that the joints which may
// still be there are to be destroyed.
public class DestroyedJoints : MonoBehaviour {
private void LateUpdate() {
Destroy(this);
}
}
}