172 lines
5.1 KiB
C#

using UnityEngine.Events;
using UnityEngine.XR.Interaction.Toolkit;
namespace UnityEngine.XR.Content.Interaction
{
public class Door : MonoBehaviour
{
[SerializeField]
HingeJoint m_DoorJoint;
[SerializeField]
[Tooltip("Transform joint that pulls a door to follow an interactor")]
TransformJoint m_DoorPuller;
[SerializeField]
GameObject m_KeyKnob;
[SerializeField]
float m_HandleOpenValue = 0.1f;
[SerializeField]
float m_HandleCloseValue = 0.5f;
[SerializeField]
float m_HingeCloseAngle = 5.0f;
[SerializeField]
float m_KeyLockValue = 0.9f;
[SerializeField]
float m_KeyUnlockValue = 0.1f;
[SerializeField]
float m_KeyPullDistance = 0.1f;
[SerializeField]
[Tooltip("Events to fire when the door is locked.")]
UnityEvent m_OnLock = new UnityEvent();
[SerializeField]
[Tooltip("Events to fire when the door is unlocked.")]
UnityEvent m_OnUnlock = new UnityEvent();
JointLimits m_OpenDoorLimits;
JointLimits m_ClosedDoorLimits;
bool m_Closed = false;
float m_LastHandleValue = 1.0f;
bool m_Locked = false;
GameObject m_KeySocket;
IXRSelectInteractable m_Key;
XRBaseInteractor m_KnobInteractor;
Transform m_KnobInteractorAttachTransform;
/// <summary>
/// Events to fire when the door is locked.
/// </summary>
public UnityEvent onLock => m_OnLock;
/// <summary>
/// Events to fire when the door is unlocked.
/// </summary>
public UnityEvent onUnlock => m_OnUnlock;
void Start()
{
m_OpenDoorLimits = m_DoorJoint.limits;
m_ClosedDoorLimits = m_OpenDoorLimits;
m_ClosedDoorLimits.min = 0.0f;
m_ClosedDoorLimits.max = 0.0f;
m_DoorJoint.limits = m_ClosedDoorLimits;
m_KeyKnob.SetActive(false);
m_Closed = true;
}
void Update()
{
// If the door is open, keep track of the hinge joint and see if it enters a state where it should close again
if (!m_Closed)
{
if (m_LastHandleValue < m_HandleCloseValue)
return;
if (Mathf.Abs(m_DoorJoint.angle) < m_HingeCloseAngle)
{
m_DoorJoint.limits = m_ClosedDoorLimits;
m_Closed = true;
}
}
if (m_KnobInteractor != null && m_KnobInteractorAttachTransform != null)
{
var distance = (m_KnobInteractorAttachTransform.position - m_KeyKnob.transform.position).magnitude;
// If over threshold, break and grant the key back to the interactor
if (distance > m_KeyPullDistance)
{
var newKeyInteractor = m_KnobInteractor;
m_KeySocket.SetActive(true);
m_Key.transform.gameObject.SetActive(true);
newKeyInteractor.interactionManager.SelectEnter(newKeyInteractor, m_Key);
m_KeyKnob.SetActive(false);
}
}
}
public void BeginDoorPulling(SelectEnterEventArgs args)
{
m_DoorPuller.connectedBody = args.interactorObject.GetAttachTransform(args.interactableObject);
m_DoorPuller.enabled = true;
}
public void EndDoorPulling()
{
m_DoorPuller.enabled = false;
m_DoorPuller.connectedBody = null;
}
public void DoorHandleUpdate(float handleValue)
{
m_LastHandleValue = handleValue;
if (!m_Closed || m_Locked)
return;
if (handleValue < m_HandleOpenValue)
{
m_DoorJoint.limits = m_OpenDoorLimits;
m_Closed = false;
}
}
public void KeyDropUpdate(SelectEnterEventArgs args)
{
m_KeySocket = args.interactorObject.transform.gameObject;
m_Key = args.interactableObject;
m_KeySocket.SetActive(false);
m_Key.transform.gameObject.SetActive(false);
m_KeyKnob.SetActive(true);
}
public void KeyUpdate(float keyValue)
{
if (!m_Locked && keyValue > m_KeyLockValue)
{
m_Locked = true;
m_OnLock.Invoke();
}
if (m_Locked && keyValue < m_KeyUnlockValue)
{
m_Locked = false;
m_OnUnlock.Invoke();
}
}
public void KeyLockSelect(SelectEnterEventArgs args)
{
m_KnobInteractor = args.interactorObject as XRBaseInteractor;
m_KnobInteractorAttachTransform = args.interactorObject.GetAttachTransform(args.interactableObject);
}
public void KeyLockDeselect(SelectExitEventArgs args)
{
m_KnobInteractor = null;
m_KnobInteractorAttachTransform = null;
}
}
}