mirror of
https://github.com/nothke/quality-control.git
synced 2025-08-11 08:03:44 +00:00
Added interaction, hand, rigidbody dragging, picking up hammer
This commit is contained in:
37
Assets/Plugins/Interaction/Runtime/Core/Interactable.cs
Normal file
37
Assets/Plugins/Interaction/Runtime/Core/Interactable.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Nothke.Interaction
|
||||
{
|
||||
public class Interactable : MonoBehaviour
|
||||
{
|
||||
[HideInInspector]
|
||||
public InteractionController manager;
|
||||
|
||||
[System.Serializable]
|
||||
public class Info
|
||||
{
|
||||
public string name;
|
||||
|
||||
//public string descriptionShort;
|
||||
//[Multiline()]
|
||||
//public string description;
|
||||
}
|
||||
|
||||
public Info info;
|
||||
public virtual string Label => info.name;
|
||||
|
||||
public virtual void Use(InteractionController im)
|
||||
{
|
||||
manager = im;
|
||||
//Debug.Log("No use");
|
||||
}
|
||||
|
||||
public virtual void OnHover() { }
|
||||
public virtual void OnDehover() { }
|
||||
|
||||
public virtual void StartHold() { }
|
||||
public virtual void EndHold() { }
|
||||
public virtual void UseHold() { }
|
||||
}
|
||||
}
|
11
Assets/Plugins/Interaction/Runtime/Core/Interactable.cs.meta
Normal file
11
Assets/Plugins/Interaction/Runtime/Core/Interactable.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db4c87c72dc0dbd418a87afc01249dad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
36
Assets/Plugins/Interaction/Runtime/Core/InteractableUtils.cs
Normal file
36
Assets/Plugins/Interaction/Runtime/Core/InteractableUtils.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nothke.Interaction
|
||||
{
|
||||
public static class InteractableUtils
|
||||
{
|
||||
|
||||
public static Vector3 GetMousePointOnPlane(Plane plane)
|
||||
{
|
||||
Vector3 screenPoint = Input.mousePosition;
|
||||
|
||||
Ray screenRay = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||||
|
||||
float e = 0;
|
||||
if (plane.Raycast(screenRay, out e))
|
||||
screenPoint.z = e;
|
||||
|
||||
return screenRay.GetPoint(e);
|
||||
}
|
||||
|
||||
public static Vector3 GetJointAnchorInWorldSpace(Joint joint)
|
||||
{
|
||||
if (!joint.connectedBody) return joint.connectedAnchor;
|
||||
|
||||
return joint.connectedBody.transform.TransformPoint(joint.connectedAnchor);
|
||||
}
|
||||
|
||||
public static bool IsNonUniform(this Transform transform)
|
||||
{
|
||||
Vector3 ls = transform.lossyScale;
|
||||
return !(Mathf.Approximately(ls.x, ls.y) && Mathf.Approximately(ls.y, ls.z));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d67801240ba9824885c0e8255eda458
|
||||
timeCreated: 1530288663
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
342
Assets/Plugins/Interaction/Runtime/Core/InteractionController.cs
Normal file
342
Assets/Plugins/Interaction/Runtime/Core/InteractionController.cs
Normal file
@@ -0,0 +1,342 @@
|
||||
//#define NEVER_MOUSE_RAY
|
||||
#define USE_FIXED_UPDATE
|
||||
|
||||
using UnityEngine;
|
||||
using Nothke.Interaction.Items;
|
||||
using Nothke.Interaction.Integration;
|
||||
|
||||
namespace Nothke.Interaction
|
||||
{
|
||||
public class InteractionController : MonoBehaviour
|
||||
{
|
||||
Transform originTransform;
|
||||
|
||||
public float interactDistance = 2;
|
||||
|
||||
public bool rayModeToggling = false;
|
||||
public bool mouseRay = false;
|
||||
|
||||
public MonoBehaviour lockableFreeLookComponent;
|
||||
ILockableFreeLook lockableFreeLook;
|
||||
|
||||
Interactable interactable;
|
||||
Interactable lastHovered;
|
||||
|
||||
public Interactable hovered { get; private set; }
|
||||
|
||||
public MonoBehaviour handsComponent;
|
||||
public IHands hands;
|
||||
public LayerMask raycastLayerMask = -1;
|
||||
|
||||
[HideInInspector]
|
||||
public Vector3 startScreenPosition;
|
||||
|
||||
[System.NonSerialized]
|
||||
public RaycastHit hit;
|
||||
[System.NonSerialized]
|
||||
public bool hasHit;
|
||||
|
||||
bool LMB;
|
||||
bool LMBup;
|
||||
bool rayModeToggleDown;
|
||||
|
||||
bool freezeDetection;
|
||||
public bool detectionFrozen => freezeDetection;
|
||||
|
||||
bool isDetached;
|
||||
bool wasMouseRayBeforeTemp;
|
||||
|
||||
public delegate void HoverAction(Interactable interactable);
|
||||
public event HoverAction OnHover;
|
||||
public delegate void DehoverAction();
|
||||
public event DehoverAction OnDehover;
|
||||
public delegate void RayModeChangeAction(bool enable);
|
||||
public event RayModeChangeAction OnRayModeChange;
|
||||
|
||||
public bool debug;
|
||||
|
||||
Camera cam;
|
||||
|
||||
protected Ray interactionRay;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (handsComponent)
|
||||
{
|
||||
hands = handsComponent.GetComponent<IHands>();
|
||||
hands.controller = this;
|
||||
Debug.Assert(hands != null, "Assigned component doesn't implement IHands");
|
||||
}
|
||||
else
|
||||
{
|
||||
hands = GetComponent<IHands>();
|
||||
if (hands != null)
|
||||
hands.controller = this;
|
||||
}
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
cam = Camera.main;
|
||||
|
||||
if (lockableFreeLookComponent)
|
||||
{
|
||||
lockableFreeLook = lockableFreeLookComponent.GetComponent<ILockableFreeLook>();
|
||||
|
||||
if (lockableFreeLook == null)
|
||||
Debug.Log("ILockableFreeLook not found on assigned component", lockableFreeLookComponent);
|
||||
}
|
||||
|
||||
originTransform = transform;
|
||||
|
||||
Dehover();
|
||||
|
||||
SetRayMode(mouseRay);
|
||||
}
|
||||
|
||||
public void SetTempRayOrigin(Transform t)
|
||||
{
|
||||
originTransform = t;
|
||||
}
|
||||
|
||||
public void ResetTempRayOrigin()
|
||||
{
|
||||
originTransform = transform;
|
||||
}
|
||||
|
||||
public void SetInput(bool interactDown, bool interactUp, bool rayModeChangeDown)
|
||||
{
|
||||
LMB = interactDown;
|
||||
LMBup = interactUp;
|
||||
this.rayModeToggleDown = rayModeChangeDown;
|
||||
}
|
||||
|
||||
public void UpdateRaycast()
|
||||
{
|
||||
if (mouseRay)
|
||||
interactionRay = cam.ScreenPointToRay(Input.mousePosition);
|
||||
else
|
||||
interactionRay = new Ray(originTransform.position, originTransform.forward);
|
||||
|
||||
hovered = null;
|
||||
|
||||
// DETECTION - Raycast
|
||||
if (!freezeDetection)
|
||||
{
|
||||
GameObject hito = GetInteractingObject();
|
||||
|
||||
if (hito)
|
||||
{
|
||||
hasHit = true;
|
||||
|
||||
hovered = hito.GetComponentInParent<Interactable>();
|
||||
|
||||
// Prevent interaction with items that don't want to be interacted with
|
||||
// unless holding a certain item
|
||||
if (hovered is IItemInHandsInteractionDependable)
|
||||
{
|
||||
if (hands == null)
|
||||
hovered = null;
|
||||
else
|
||||
if (!(hovered as IItemInHandsInteractionDependable).IsInteractableIfHolding(hands.item))
|
||||
hovered = null;
|
||||
}
|
||||
|
||||
// Prevent interaction if item in hands prevents interaction
|
||||
if (hands != null && hands.item && hands.item is IEnvironmentInteractionPreventable eip)
|
||||
{
|
||||
if (!eip.EnvironmentInteractionIsAllowed)
|
||||
hovered = null;
|
||||
}
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
if (hovered is ISelectiveInteractable)
|
||||
{
|
||||
if (!(hovered as ISelectiveInteractable).CanInteract)
|
||||
hovered = null;
|
||||
}
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
if (hovered is ICanInteract)
|
||||
{
|
||||
if (!(hovered as ICanInteract).CanInteract(this))
|
||||
hovered = null;
|
||||
}
|
||||
|
||||
if (hovered != lastHovered && hovered != null)
|
||||
Hover(hovered);
|
||||
}
|
||||
else hasHit = false;
|
||||
|
||||
if (hovered != lastHovered && hovered == null)
|
||||
Dehover();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this to provide a custom raycaster for example. You can get the default provided ray from interactionRay.
|
||||
/// </summary>
|
||||
protected virtual GameObject GetInteractingObject()
|
||||
{
|
||||
if (Physics.Raycast(interactionRay, out hit, interactDistance, raycastLayerMask))
|
||||
return hit.collider.gameObject;
|
||||
else return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call this after you set input. Should be called in Update()
|
||||
/// </summary>
|
||||
public void UpdateInput()
|
||||
{
|
||||
// On click
|
||||
bool interactedThisFrame = false;
|
||||
if (hovered && LMB)
|
||||
{
|
||||
interactable = hovered;
|
||||
|
||||
if (hands != null && interactable is ITakeable)
|
||||
{
|
||||
if (interactable is ISelectiveTakeable)
|
||||
{
|
||||
if ((interactable as ISelectiveTakeable).CanBeTaken())
|
||||
hands.Take(interactable as ITakeable);
|
||||
}
|
||||
else
|
||||
hands.Take(interactable as ITakeable);
|
||||
}
|
||||
|
||||
interactable.Use(this);
|
||||
interactable.StartHold();
|
||||
interactedThisFrame = true;
|
||||
|
||||
startScreenPosition = Input.mousePosition;
|
||||
}
|
||||
|
||||
// On scroll
|
||||
if (hovered && hovered is IScrollInteractable scrollInteractable)
|
||||
{
|
||||
float scroll = Input.mouseScrollDelta.y;
|
||||
|
||||
if (scroll != 0)
|
||||
scrollInteractable.Scroll(this, scroll);
|
||||
}
|
||||
|
||||
// On release
|
||||
if (interactable && LMBup)
|
||||
{
|
||||
interactable.EndHold();
|
||||
interactable = null;
|
||||
}
|
||||
|
||||
lastHovered = hovered;
|
||||
|
||||
LMB = false;
|
||||
LMBup = false;
|
||||
|
||||
if (!interactedThisFrame && hands != null)
|
||||
hands.UpdateInteraction();
|
||||
}
|
||||
|
||||
public void Recast()
|
||||
{
|
||||
hovered = null;
|
||||
}
|
||||
|
||||
void ToggleRayMode()
|
||||
{
|
||||
mouseRay = !mouseRay;
|
||||
|
||||
SetRayMode(mouseRay);
|
||||
}
|
||||
|
||||
public void FreezeDetection()
|
||||
{
|
||||
freezeDetection = true;
|
||||
hovered = null;
|
||||
}
|
||||
|
||||
public void UnfreezeDetection()
|
||||
{
|
||||
freezeDetection = false;
|
||||
Dehover();
|
||||
Recast();
|
||||
}
|
||||
|
||||
public void SetTempMouseRay(bool tempMouse)
|
||||
{
|
||||
if (tempMouse)
|
||||
{
|
||||
wasMouseRayBeforeTemp = mouseRay;
|
||||
SetRayMode(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!wasMouseRayBeforeTemp)
|
||||
{
|
||||
SetRayMode(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRayMode(bool isMouse)
|
||||
{
|
||||
mouseRay = isMouse;
|
||||
|
||||
#if !NEVER_MOUSE_RAY
|
||||
if (mouseRay)
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
|
||||
// TODO: if windows
|
||||
//System.Windows.Forms.Cursor.Position = new System.Drawing.Point(10, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
//System.Windows.Forms.Cursor.Position = new System.Drawing.Point(Screen.width / 2, Screen.height / 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lockableFreeLook != null)
|
||||
lockableFreeLook.LockFreeLook(mouseRay);
|
||||
else
|
||||
Debug.LogWarning("No freelook lockable");
|
||||
|
||||
OnRayModeChange?.Invoke(mouseRay);
|
||||
|
||||
if (debug)
|
||||
Debug.Log("Ray mode changed to " + (mouseRay ? " Mouse" : " Center"));
|
||||
|
||||
//Cursor.visible = mouseRay;
|
||||
|
||||
if (hands != null)
|
||||
hands.isFixed = mouseRay;
|
||||
}
|
||||
|
||||
void Hover(Interactable interactable)
|
||||
{
|
||||
interactable.OnHover();
|
||||
OnHover?.Invoke(interactable);
|
||||
|
||||
if (debug)
|
||||
Debug.Log("Hovered " + interactable.name);
|
||||
}
|
||||
|
||||
void Dehover()
|
||||
{
|
||||
if (lastHovered)
|
||||
lastHovered.OnDehover();
|
||||
|
||||
OnDehover?.Invoke();
|
||||
|
||||
if (debug)
|
||||
Debug.Log("Dehovered");
|
||||
}
|
||||
|
||||
public void LockFreeLook(bool b)
|
||||
{
|
||||
if (lockableFreeLook != null)
|
||||
lockableFreeLook.LockFreeLook(b);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb45815bc5df925448fc604ec327964b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
145
Assets/Plugins/Interaction/Runtime/Core/InteractionInterfaces.cs
Normal file
145
Assets/Plugins/Interaction/Runtime/Core/InteractionInterfaces.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nothke.Interaction
|
||||
{
|
||||
public interface IScrollInteractable
|
||||
{
|
||||
void Scroll(InteractionController im, float scroll);
|
||||
}
|
||||
|
||||
[System.Obsolete("Use ICanInteract instead")]
|
||||
public interface ISelectiveInteractable
|
||||
{
|
||||
bool CanInteract { get; }
|
||||
}
|
||||
|
||||
public interface ICanInteract
|
||||
{
|
||||
bool CanInteract(InteractionController controller);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Nothke.Interaction.Items
|
||||
{
|
||||
public interface IUsable
|
||||
{
|
||||
void Use();
|
||||
}
|
||||
|
||||
public interface IHoldUsable
|
||||
{
|
||||
void UseEnd();
|
||||
}
|
||||
|
||||
public interface IScrollableInHand
|
||||
{
|
||||
void ScrollInHand(float scroll);
|
||||
}
|
||||
|
||||
public interface ISecondaryUsable
|
||||
{
|
||||
bool AllowExamination { get; }
|
||||
void UseSecondary();
|
||||
}
|
||||
|
||||
public interface ITakeable
|
||||
{
|
||||
Transform Transform { get; }
|
||||
Rigidbody Rigidbody { get; }
|
||||
void OnTaken(IHands hands);
|
||||
}
|
||||
|
||||
public interface ICustomHoldPivot
|
||||
{
|
||||
void GetHoldPivot(out Vector3 holdPos, out Quaternion holdRot);
|
||||
}
|
||||
|
||||
public interface IHands
|
||||
{
|
||||
Interactable item { get; }
|
||||
void Take(ITakeable _item);
|
||||
void Drop();
|
||||
void DropFixed();
|
||||
void UpdateInteraction();
|
||||
bool isFixed { get; set; }
|
||||
void Place(Vector3 position, Quaternion rotation, Transform relativeParent, IItemReceivable intoSlot = null);
|
||||
InteractionController controller { get; set; }
|
||||
}
|
||||
|
||||
public interface ISelectiveTakeable
|
||||
{
|
||||
bool CanBeTaken();
|
||||
}
|
||||
|
||||
public interface IDroppable
|
||||
{
|
||||
Transform Transform { get; }
|
||||
Rigidbody Rigidbody { get; }
|
||||
void OnDropped(IHands hands);
|
||||
bool DelayDrop { get; }
|
||||
}
|
||||
|
||||
public interface IThrowable
|
||||
{
|
||||
Rigidbody Rigidbody { get; }
|
||||
bool canThrow { get; }
|
||||
float minThrowAcceleration { get; }
|
||||
float maxThrowAcceleration { get; }
|
||||
void OnDropped(IHands hands);
|
||||
}
|
||||
|
||||
public interface INicePlaceable
|
||||
{
|
||||
void GetPlacePivot(out Vector3 placePos, out Quaternion placeRot);
|
||||
void OnStartedPlacing(IHands hands);
|
||||
void OnNicePlaced(IHands hands);
|
||||
}
|
||||
|
||||
public interface IExaminable
|
||||
{
|
||||
float HorizontalAngle { get; }
|
||||
float VerticalAngle { get; }
|
||||
}
|
||||
|
||||
public interface ICustomExaminePosition
|
||||
{
|
||||
Vector3 ExaminePosition { get; }
|
||||
}
|
||||
|
||||
public interface ICustomHandPosition
|
||||
{
|
||||
Vector3 HandsOffset { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets position of held hand
|
||||
/// </summary>
|
||||
public interface IOverrideHandPositon
|
||||
{
|
||||
Vector3 HandPosition { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds offset translation to held hand
|
||||
/// </summary>
|
||||
public interface IOffsetHandPosition
|
||||
{
|
||||
Vector3 HandPositionOffset { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement this if you want to prevent held items interacting with other (environment) interactables
|
||||
/// </summary>
|
||||
public interface IEnvironmentInteractionPreventable
|
||||
{
|
||||
bool EnvironmentInteractionIsAllowed { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement this on interactables that you want to be interactable only if the player is holding a certain item
|
||||
/// </summary>
|
||||
public interface IItemInHandsInteractionDependable
|
||||
{
|
||||
bool IsInteractableIfHolding(Interactable item);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6a61181c3b9a7d40a2516b501df78c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user