/// <summary> /// Release an object without throwing it. /// </summary> /// <param name="grabbable">Object to release</param> public virtual void OffhandGrabbed(Grabbable grabbable) { if (GrabbedObject == grabbable) { ReleaseGrabbedObject(Vector3.zero, Vector3.zero); } }
/// <summary> /// Unsuscribe an object from the list of touched grabbables. /// The object will not be a grabbing candidate until it is touched again. /// </summary> /// <param name="grabbable">The grabbable to be unsuscribed</param> public void ForceUntouch(Grabbable grabbable) { if (_grabCandidates.ContainsKey(grabbable)) { _grabCandidates.Remove(grabbable); } }
public void OnTriggerExit(Collider otherCollider) { Grabbable grabbable = otherCollider.GetComponent <Grabbable>() ?? otherCollider.GetComponentInParent <Grabbable>(); if (grabbable == null) { return; } bool found = _grabCandidates.TryGetValue(grabbable, out int refCount); if (!found) { return; } if (refCount > 1) { _grabCandidates[grabbable] = refCount - 1; } else { _grabCandidates.Remove(grabbable); if (_grabCandidates.Count == 0) { _lastGrabCandidate = grabbable; _timeWithoutCandidates = Time.timeSinceLevelLoad; } } }
/// <summary> /// Unsuscribe all the objects grabbed by all hands. /// </summary> /// <param name="grabbable"></param> public static void ClearAllGrabs(Grabbable grabbable) { foreach (var grabber in allGrabbers) { grabber.ForceUntouch(grabbable); grabber.ForceRelease(grabbable); } }
/// <summary> /// Attach a given grabbable to the hand, storing the offset to the hand so it can be kept while holding. /// </summary> /// <param name="closestGrabbable">The object to be grabbed.</param> /// <param name="closestGrabbableCollider">The collider of the grabbable, not used.</param> protected virtual void Grab(Grabbable closestGrabbable, Collider closestGrabbableCollider) { GrabbedObject = closestGrabbable; GrabbedObject.GrabBegin(this, closestGrabbableCollider); OnGrabStarted?.Invoke(GrabbedObject?.gameObject); _grabbedObjectOffset = new Pose(); _grabbedObjectOffset.position = Quaternion.Inverse(transform.rotation) * (GrabbedObject.transform.position - transform.position); _grabbedObjectOffset.rotation = Quaternion.Inverse(transform.rotation) * GrabbedObject.transform.rotation; }
/// <summary> /// Search for a nearby object and grab it. /// </summary> protected virtual void GrabBegin() { Grabbable closestGrabbable = FindClosestGrabbable(); GrabVolumeEnable(false); if (closestGrabbable != null) { _timeSinceLastRelease = Time.timeSinceLevelLoad; Grab(closestGrabbable); } }
/// <summary> /// Release a grabbable from this grabber. /// </summary> /// <param name="grabbable">The grabbable to be released.</param> public void ForceRelease(Grabbable grabbable) { bool canRelease = ( (GrabbedObject != null) && (GrabbedObject == grabbable || grabbable == null) ); if (canRelease) { GrabEnd(false); } }
/// <summary> /// Attach a given grabbable to the hand, storing the offset to the hand so it can be kept while holding. /// </summary> /// <param name="closestGrabbable">The object to be grabbed.</param> protected virtual void Grab(Grabbable closestGrabbable) { _timeSinceLastGrab = Time.timeSinceLevelLoad; GrabbedObject = closestGrabbable; GrabbedObject?.GrabBegin(this); OnGrabStarted?.Invoke(GrabbedObject?.gameObject); Transform grabedTransform = closestGrabbable.transform; _grabbedObjectOffset = new Pose(); _grabbedObjectOffset.position = Quaternion.Inverse(this.transform.rotation) * (grabedTransform.position - this.transform.position); _grabbedObjectOffset.rotation = Quaternion.Inverse(this.transform.rotation) * grabedTransform.rotation; }
private void BeginDistantGrab() { Grabbable distantGrabbable = FindDistantGrabbable(); if (distantGrabbable != null) { ObjectSnappingAddress snapAddress = this.GetComponent <Snapper>()?.SnapForGrabbable(distantGrabbable.gameObject); //TODO reference to snapper? if (snapAddress != null && snapAddress.point.CanBeDistantGrabbed) { _distantGrabAddress = snapAddress; } } }
private void OnTriggerEnter(Collider otherCollider) { Grabbable grabbable = otherCollider.GetComponent <Grabbable>() ?? otherCollider.GetComponentInParent <Grabbable>(); if (grabbable == null) { return; } int refCount = 0; _grabCandidates.TryGetValue(grabbable, out refCount); _grabCandidates[grabbable] = refCount + 1; }
/// <summary> /// Search for a nearby object and grab it. /// </summary> protected virtual void GrabBegin(Grabbable closestGrabbable = null) { closestGrabbable = closestGrabbable ?? FindClosestGrabbable(); GrabVolumeEnable(false); if (closestGrabbable != null) { CancelDistantGrab(); _timeSinceLastRelease = Time.timeSinceLevelLoad; Grab(closestGrabbable); } else { BeginDistantGrab(); } }
public void OnTriggerEnter(Collider otherCollider) { Grabbable grabbable = otherCollider.GetComponent <Grabbable>() ?? otherCollider.GetComponentInParent <Grabbable>(); if (grabbable == null) { return; } _grabCandidates.TryGetValue(grabbable, out int refCount); _grabCandidates[grabbable] = refCount + 1; _timeWithoutCandidates = null; _lastGrabCandidate = null; }
protected virtual void GrabFailed() { bool sentFailedEventRecently = _timeSinceLastFail.HasValue && Time.timeSinceLevelLoad - _timeSinceLastFail.Value < GRAB_ATTEMPT_DURATION; if (!sentFailedEventRecently) { Grabbable failedGrabbable = _lastGrabCandidate; if (failedGrabbable == null) { failedGrabbable = FindClosestGrabbable(); } OnGrabAttemptFail?.Invoke(failedGrabbable?.gameObject); _timeSinceLastFail = Time.timeSinceLevelLoad; } }
protected Grabbable FindClosestGrabbable() { float closestMagSq = float.MaxValue; Grabbable closestGrabbable = null; foreach (Grabbable grabbable in _grabCandidates.Keys) { Collider collider = FindClosestCollider(grabbable, out float distance); if (distance < closestMagSq) { closestMagSq = distance; closestGrabbable = grabbable; } } return(closestGrabbable); }
private Grabbable FindDistantGrabbable() { Vector3 origin = gripTransform.position + gripTransform.forward * minMaxDistanceGrab.x; float lenght = Mathf.Abs(minMaxDistanceGrab.x - minMaxDistanceGrab.y); if (Physics.SphereCast(origin, DISTANT_SEARCH_RADIOUS, gripTransform.forward, out RaycastHit hit, lenght, ~(distantIgnoreLayers.value), QueryTriggerInteraction.Ignore)) { Grabbable grabbable = hit.transform.GetComponentInParent <Grabbable>(); if (grabbable != null && !grabbable.IsGrabbed) { return(grabbable); } } return(null); }
/// <summary> /// Triggers how close the grabber is to start grabbing a nearby object, informing the snapping system. /// </summary> /// <param name="factor">Current normalised value for the grab attemp, 1 indicates a grab.</param> protected void NearGrab(float factor) { if (factor == 0f) { OnGrabAttemp?.Invoke(null, 0f); return; } Grabbable closestGrabbable = FindClosestGrabbable(); if (closestGrabbable != null) { OnGrabAttemp?.Invoke(closestGrabbable.gameObject, factor); } else { OnGrabAttemp?.Invoke(null, 0f); } }
private Collider FindClosestCollider(Grabbable grabbable, out float score) { float closestMagSq = float.MaxValue; Collider closestGrabbableCollider = null; for (int j = 0; j < grabbable.GrabPoints.Length; ++j) { Collider grabbableCollider = grabbable.GrabPoints[j]; if (grabbableCollider == null) { continue; } Vector3 closestPointOnBounds = grabbableCollider.ClosestPointOnBounds(gripTransform.position); float grabbableMagSq = (gripTransform.position - closestPointOnBounds).sqrMagnitude; if (grabbableMagSq < closestMagSq) { closestMagSq = grabbableMagSq; closestGrabbableCollider = grabbableCollider; } } score = closestMagSq; return(closestGrabbableCollider); }
private void OnTriggerExit(Collider otherCollider) { Grabbable grabbable = otherCollider.GetComponent <Grabbable>() ?? otherCollider.GetComponentInParent <Grabbable>(); if (grabbable == null) { return; } bool found = _grabCandidates.TryGetValue(grabbable, out int refCount); if (!found) { return; } if (refCount > 1) { _grabCandidates[grabbable] = refCount - 1; } else { _grabCandidates.Remove(grabbable); } }