Added interaction, hand, rigidbody dragging, picking up hammer

This commit is contained in:
nothke
2024-08-18 13:21:38 +02:00
parent 93ecc95bfa
commit d2c3dff101
76 changed files with 5079 additions and 4 deletions

View 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() { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: db4c87c72dc0dbd418a87afc01249dad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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));
}
}
}

View File

@@ -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:

View 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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb45815bc5df925448fc604ec327964b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d6a61181c3b9a7d40a2516b501df78c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: