XRoom_Unity/Assets/Photon/FusionXRHost/Scripts/Grabbing/Grabber.cs
2025-05-31 10:20:20 +03:30

150 lines
5.0 KiB
C#

using Fusion.XR.Host.Rig;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Fusion.XR.Host.Grabbing
{
public class Grabber : MonoBehaviour
{
public Grabbable grabbedObject;
Collider lastCheckedCollider;
Grabbable lastCheckColliderGrabbable;
HardwareHand hand;
HardwareRig rig;
public Vector3 ungrabPosition;
public Quaternion ungrabRotation;
public Vector3 ungrabVelocity;
public Vector3 ungrabAngularVelocity;
// Will be set by the NetworkGrabber for the local user itself, when it spawns
public NetworkGrabber networkGrabber;
public bool resetGrabInfo = false;
GrabInfo _grabInfo;
public GrabInfo GrabInfo
{
get
{
if (resetGrabInfo)
return default;
if (grabbedObject)
{
_grabInfo.grabbedObjectId = grabbedObject.networkGrabbable.Id;
_grabInfo.localPositionOffset = grabbedObject.localPositionOffset;
_grabInfo.localRotationOffset = grabbedObject.localRotationOffset;
}
else
{
_grabInfo.grabbedObjectId = NetworkBehaviourId.None;
_grabInfo.ungrabPosition = ungrabPosition;
_grabInfo.ungrabRotation = ungrabRotation;
_grabInfo.ungrabVelocity = ungrabVelocity;
_grabInfo.ungrabAngularVelocity = ungrabAngularVelocity;
}
return _grabInfo;
}
}
private void Awake()
{
hand = GetComponentInParent<HardwareHand>();
rig = GetComponentInParent<HardwareRig>();
}
private void OnTriggerStay(Collider other)
{
if (rig && rig.runner && rig.runner.IsResimulation)
{
// We only manage grabbing during forward ticks, to avoid detecting past positions of the grabbable object
return;
}
// Exit if an object is already grabbed
if (grabbedObject != null)
{
// It is already the grabbed object or another, but we don't allow shared grabbing here
return;
}
Grabbable grabbable;
if (lastCheckedCollider == other)
{
grabbable = lastCheckColliderGrabbable;
}
else
{
grabbable = other.GetComponentInParent<Grabbable>();
}
// To limit the number of GetComponent calls, we cache the latest checked collider grabbable result
lastCheckedCollider = other;
lastCheckColliderGrabbable = grabbable;
if (grabbable != null)
{
if (grabbable.currentGrabber != null)
{
// We don't allow multihand grabbing (it would have to be defined), nor hand swap (it would require to track hovering and do not allow grabbing while the hand is already close - or any other mecanism to avoid infinit swapping between the hands)
return;
}
if (hand.isGrabbing) Grab(grabbable);
}
}
private void Update()
{
if (rig && rig.runner && rig.runner.IsResimulation)
{
// We only manage grabbing during forward ticks, to avoid detecting past positions of the grabbable object
return;
}
if (grabbedObject != null && grabbedObject.currentGrabber != this)
{
// This object as been grabbed by another hand, no need to trigger an ungrab
grabbedObject = null;
}
// Check if the local hand is still grabbing the object
if (grabbedObject != null && !hand.isGrabbing)
{
// Object released by this hand
Ungrab(grabbedObject);
}
}
// Ask the grabbable object to start following the hand
public void Grab(Grabbable grabbable)
{
Debug.Log($"Try to grab object {grabbable.gameObject.name} with {gameObject.name}");
if (grabbable.Grab(this))
{
grabbedObject = grabbable;
}
}
// Ask the grabbable object to stop following the hand
public void Ungrab(Grabbable grabbable)
{
Debug.Log($"Try to ungrab object {grabbable.gameObject.name} with {gameObject.name}");
if (grabbable.networkGrabbable)
{
ungrabPosition = grabbedObject.networkGrabbable.transform.position;
ungrabRotation = grabbedObject.networkGrabbable.transform.rotation;
ungrabVelocity = grabbedObject.Velocity;
ungrabAngularVelocity = grabbedObject.AngularVelocity;
}
grabbedObject.Ungrab();
grabbedObject = null;
}
}
}