// Headset Collision|Presence|70010
namespace VRTK
{
using UnityEngine;
///
/// Event Payload
///
/// The Collider of the game object the headset has collided with.
/// The current Transform of the object that the Headset Collision Fade script is attached to (Camera).
public struct HeadsetCollisionEventArgs
{
public Collider collider;
public Transform currentTransform;
}
///
/// Event Payload
///
/// this object
///
public delegate void HeadsetCollisionEventHandler(object sender, HeadsetCollisionEventArgs e);
///
/// Denotes when the HMD is colliding with valid geometry.
///
///
/// **Script Usage:**
/// * Place the `VRTK_HeadsetCollision` script on any active scene GameObject.
///
///
/// `VRTK/Examples/011_Camera_HeadSetCollisionFading` has collidable walls around the play area and if the user puts their head into any of the walls then the headset will fade to black.
///
[AddComponentMenu("VRTK/Scripts/Presence/VRTK_HeadsetCollision")]
public class VRTK_HeadsetCollision : MonoBehaviour
{
[Tooltip("If this is checked then the headset collision will ignore colliders set to `Is Trigger = true`.")]
public bool ignoreTriggerColliders = false;
[Tooltip("The radius of the auto generated sphere collider for detecting collisions on the headset.")]
public float colliderRadius = 0.1f;
[Tooltip("A specified VRTK_PolicyList to use to determine whether any objects will be acted upon by the Headset Collision.")]
public VRTK_PolicyList targetListPolicy;
///
/// Emitted when the user's headset collides with another game object.
///
public event HeadsetCollisionEventHandler HeadsetCollisionDetect;
///
/// Emitted when the user's headset stops colliding with a game object.
///
public event HeadsetCollisionEventHandler HeadsetCollisionEnded;
///
/// Determines if the headset is currently colliding with another object.
///
[HideInInspector]
public bool headsetColliding = false;
///
/// Stores the collider of what the headset is colliding with.
///
[HideInInspector]
public Collider collidingWith = null;
protected Transform headset;
protected VRTK_HeadsetCollider headsetColliderScript;
protected GameObject headsetColliderContainer;
protected bool generateCollider = false;
protected bool generateRigidbody = false;
public virtual void OnHeadsetCollisionDetect(HeadsetCollisionEventArgs e)
{
if (HeadsetCollisionDetect != null)
{
HeadsetCollisionDetect(this, e);
}
}
public virtual void OnHeadsetCollisionEnded(HeadsetCollisionEventArgs e)
{
if (HeadsetCollisionEnded != null)
{
HeadsetCollisionEnded(this, e);
}
}
///
/// The IsColliding method is used to determine if the headset is currently colliding with a valid game object and returns true if it is and false if it is not colliding with anything or an invalid game object.
///
/// Returns `true` if the headset is currently colliding with a valid game object.
public virtual bool IsColliding()
{
return headsetColliding;
}
///
/// The GetHeadsetColliderContainer method returns the auto generated GameObject that contains the headset collider.
///
/// The auto generated headset collider GameObject.
public virtual GameObject GetHeadsetColliderContainer()
{
return headsetColliderContainer;
}
protected virtual void Awake()
{
VRTK_SDKManager.AttemptAddBehaviourToToggleOnLoadedSetupChange(this);
}
protected virtual void OnEnable()
{
headset = VRTK_DeviceFinder.HeadsetTransform();
if (headset != null)
{
headsetColliding = false;
SetupHeadset();
VRTK_PlayerObject.SetPlayerObject(headsetColliderContainer.gameObject, VRTK_PlayerObject.ObjectTypes.Headset);
}
}
protected virtual void OnDisable()
{
if (headset != null && headsetColliderScript != null)
{
headsetColliderScript.EndCollision(collidingWith);
TearDownHeadset();
}
}
protected virtual void OnDestroy()
{
VRTK_SDKManager.AttemptRemoveBehaviourToToggleOnLoadedSetupChange(this);
}
protected virtual void Update()
{
if (headsetColliderContainer != null && headsetColliderContainer.transform.parent != headset)
{
headsetColliderContainer.transform.SetParent(headset);
headsetColliderContainer.transform.localPosition = Vector3.zero;
headsetColliderContainer.transform.localRotation = headset.localRotation;
}
}
protected virtual void CreateHeadsetColliderContainer()
{
if (headsetColliderContainer == null)
{
headsetColliderContainer = new GameObject(VRTK_SharedMethods.GenerateVRTKObjectName(true, "HeadsetColliderContainer"));
headsetColliderContainer.transform.position = Vector3.zero;
headsetColliderContainer.transform.localRotation = headset.localRotation;
headsetColliderContainer.transform.localScale = Vector3.one;
headsetColliderContainer.layer = LayerMask.NameToLayer("Ignore Raycast");
}
}
protected virtual void SetupHeadset()
{
Rigidbody headsetRigidbody = headset.GetComponentInChildren();
if (headsetRigidbody == null)
{
CreateHeadsetColliderContainer();
headsetRigidbody = headsetColliderContainer.AddComponent();
headsetRigidbody.constraints = RigidbodyConstraints.FreezeAll;
generateRigidbody = true;
}
headsetRigidbody.isKinematic = true;
headsetRigidbody.useGravity = false;
Collider headsetCollider = headset.GetComponentInChildren();
if (headsetCollider == null)
{
CreateHeadsetColliderContainer();
SphereCollider newCollider = headsetColliderContainer.gameObject.AddComponent();
newCollider.radius = colliderRadius;
headsetCollider = newCollider;
generateCollider = true;
}
headsetCollider.isTrigger = true;
if (headsetColliderScript == null)
{
GameObject attachTo = (headsetColliderContainer ? headsetColliderContainer : headset.gameObject);
headsetColliderScript = attachTo.AddComponent();
headsetColliderScript.SetParent(gameObject);
headsetColliderScript.SetIgnoreTarget(targetListPolicy);
}
}
protected virtual void TearDownHeadset()
{
if (generateCollider)
{
Destroy(headset.gameObject.GetComponent());
}
if (generateRigidbody)
{
Destroy(headset.gameObject.GetComponent());
}
if (headsetColliderScript != null)
{
Destroy(headsetColliderScript);
}
if (headsetColliderContainer != null)
{
Destroy(headsetColliderContainer);
}
}
}
public class VRTK_HeadsetCollider : MonoBehaviour
{
protected VRTK_HeadsetCollision parent;
protected VRTK_PolicyList targetListPolicy;
public virtual void SetParent(GameObject setParent)
{
parent = setParent.GetComponent();
}
public virtual void SetIgnoreTarget(VRTK_PolicyList list = null)
{
targetListPolicy = list;
}
public virtual void EndCollision(Collider collider)
{
if (collider == null || !VRTK_PlayerObject.IsPlayerObject(collider.gameObject))
{
parent.headsetColliding = false;
parent.collidingWith = null;
parent.OnHeadsetCollisionEnded(SetHeadsetCollisionEvent(collider, transform));
}
}
protected virtual void OnTriggerStay(Collider collider)
{
if (parent.ignoreTriggerColliders && collider != null && collider.isTrigger)
{
return;
}
if (enabled && !VRTK_PlayerObject.IsPlayerObject(collider.gameObject) && ValidTarget(collider.transform))
{
parent.headsetColliding = true;
parent.collidingWith = collider;
parent.OnHeadsetCollisionDetect(SetHeadsetCollisionEvent(collider, transform));
}
}
protected virtual void OnTriggerExit(Collider collider)
{
if (parent.ignoreTriggerColliders && collider != null && collider.isTrigger)
{
return;
}
EndCollision(collider);
}
protected virtual void Update()
{
if (parent.headsetColliding && (parent.collidingWith == null || !parent.collidingWith.gameObject.activeInHierarchy))
{
EndCollision(parent.collidingWith);
}
}
protected virtual HeadsetCollisionEventArgs SetHeadsetCollisionEvent(Collider collider, Transform currentTransform)
{
HeadsetCollisionEventArgs e;
e.collider = collider;
e.currentTransform = currentTransform;
return e;
}
protected virtual bool ValidTarget(Transform target)
{
return (target != null && !(VRTK_PolicyList.Check(target.gameObject, targetListPolicy)));
}
}
}