From 77212505b2cf4d4151c96f7cc6993ea0be8ee88f Mon Sep 17 00:00:00 2001 From: Xenira <1288524+Xenira@users.noreply.github.com> Date: Wed, 6 Mar 2024 23:21:31 +0100 Subject: [PATCH] feat(behaviours): add grabable (#19) --- plugin/src/objects/behaviours/Grabable.cs | 83 +++++++++++++++++++++++ plugin/src/util/Option.cs | 15 ++++ 2 files changed, 98 insertions(+) create mode 100644 plugin/src/objects/behaviours/Grabable.cs diff --git a/plugin/src/objects/behaviours/Grabable.cs b/plugin/src/objects/behaviours/Grabable.cs new file mode 100644 index 0000000..a952f61 --- /dev/null +++ b/plugin/src/objects/behaviours/Grabable.cs @@ -0,0 +1,83 @@ +using System.Linq; +using PiUtils.Util; +using UnityEngine; + +namespace PiUtils.Objects.Behaviours; +public class Grabable : MonoBehaviour +{ + private static readonly PluginLogger Logger = PluginLogger.GetLogger(); + + public bool IsGrabbed { get; private set; } = false; + public bool IsHovered { get; private set; } = false; + + public float grabDistance = 0.2f; + + public bool snapToHand = false; + public Option grabOffset = Option.None(); + public Option grabRotation = Option.None(); + + public Transform originalParent { get; private set; } + + public Grabable() { } + + public Grabable(float? grabDistance, bool snapToHand, Option grabOffset, Option grabRotation) + { + this.grabDistance = grabDistance ?? this.grabDistance; + this.snapToHand = snapToHand; + this.grabOffset = grabOffset; + this.grabRotation = grabRotation; + } + + public bool TryGrab(Transform grabbingTransform) + { + if (IsGrabbed) + { + Logger.LogDebug("Object already grabbed: " + gameObject.name); + return false; + } + + var distance = Vector3.Distance(transform.position, grabbingTransform.position); + if (grabDistance >= 0 && distance >= grabDistance) + { + Logger.LogDebug($"Object too far to grab: {gameObject.name} ({distance} > {grabDistance})"); + return false; + } + + Grab(grabbingTransform); + return IsGrabbed; + } + + public void Grab(Transform grabbingTransform) + { + if (IsGrabbed) + { + return; + } + + Logger.LogDebug("Grabbing object: " + gameObject.name); + + IsGrabbed = true; + originalParent = transform.parent; + + if (snapToHand) + { + transform.position = grabbingTransform.position + grabOffset.FirstOrDefault(); + transform.rotation = grabbingTransform.rotation * grabRotation.FirstOrDefault(); + } + + transform.SetParent(grabbingTransform, true); + } + + public void Release() + { + if (!IsGrabbed) + { + return; + } + + IsGrabbed = false; + transform.SetParent(originalParent, true); + + originalParent = null; + } +} diff --git a/plugin/src/util/Option.cs b/plugin/src/util/Option.cs index a9ddb6c..991d0ca 100644 --- a/plugin/src/util/Option.cs +++ b/plugin/src/util/Option.cs @@ -11,6 +11,16 @@ private Option(T[] data) this.data = data; } + public static Option New(T value) + { + if (value == null) + { + return None(); + } + + return Some(value); + } + public static Option Some(T value) { return new Option([value]); @@ -21,6 +31,11 @@ public static Option None() return new Option([]); } + public bool IsSome() + { + return data.Length > 0; + } + public IEnumerator GetEnumerator() { return ((IEnumerable)data).GetEnumerator();