Replace UltimateXR with HurricaneVR
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e538dc1865da2ed41b9f803e3e586405
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components.Creators
|
||||
{
|
||||
public class HVRPhysicsLeverCreator : MonoBehaviour
|
||||
{
|
||||
public Transform Anchor;
|
||||
public Transform Lever;
|
||||
public HVRAxis Axis;
|
||||
public float Mass = 5f;
|
||||
public float MinAngle = 90f;
|
||||
public float MaxAngle = 90f;
|
||||
public float GrabbedDamper = 3f;
|
||||
public float Damper = 10f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1b17ef000f068b468782f079bd24ba6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
97
Assets/HurricaneVR/Framework/Scripts/Components/HVRButton.cs
Normal file
97
Assets/HurricaneVR/Framework/Scripts/Components/HVRButton.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic button check for travel along a defined axis, requires the user to have setup their own constraint system.
|
||||
/// Superceded by the new HVRPhysicsButton component which helps create joints and limits for you
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public class HVRButton : MonoBehaviour
|
||||
{
|
||||
public VRButtonEvent ButtonDown = new VRButtonEvent();
|
||||
public VRButtonEvent ButtonUp = new VRButtonEvent();
|
||||
|
||||
|
||||
public Vector3 Axis;
|
||||
|
||||
[Tooltip("How far the button must travel to become pressed.")]
|
||||
public float Threshold;
|
||||
[Tooltip("Threshold to hit on the return to allow the button to be pressed again.")]
|
||||
public float UpThreshold;
|
||||
[Tooltip("The resting position of the button")]
|
||||
public Vector3 StartPosition;
|
||||
public bool IsPressed = false;
|
||||
|
||||
public AudioClip AudioButtonDown;
|
||||
public AudioClip AudioButtonUp;
|
||||
|
||||
public Rigidbody Rigidbody { get; private set; }
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
//for older projects that wouldn't have set this in the editor
|
||||
if(StartPosition == Vector3.zero)
|
||||
{
|
||||
StartPosition = transform.localPosition;
|
||||
}
|
||||
|
||||
Rigidbody = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
var distance = (StartPosition - transform.localPosition).magnitude;
|
||||
|
||||
if (!IsPressed && distance >= Threshold)
|
||||
{
|
||||
IsPressed = true;
|
||||
OnButtonDown();
|
||||
}
|
||||
else if (IsPressed && distance < UpThreshold)
|
||||
{
|
||||
IsPressed = false;
|
||||
OnButtonUp();
|
||||
}
|
||||
|
||||
ClampBounds();
|
||||
}
|
||||
|
||||
private void ClampBounds()
|
||||
{
|
||||
var test = new Vector3(transform.localPosition.x * Axis.x, transform.localPosition.y * Axis.y, transform.localPosition.z * Axis.z);
|
||||
|
||||
if (test.x > StartPosition.x || test.y > StartPosition.y || test.z > StartPosition.z)
|
||||
{
|
||||
transform.localPosition = StartPosition;
|
||||
Rigidbody.velocity = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
ClampBounds();
|
||||
}
|
||||
|
||||
protected virtual void OnButtonDown()
|
||||
{
|
||||
if (AudioButtonDown)
|
||||
if(SFXPlayer.Instance) SFXPlayer.Instance.PlaySFX(AudioButtonDown, transform.position);
|
||||
|
||||
ButtonDown.Invoke(this);
|
||||
}
|
||||
|
||||
protected virtual void OnButtonUp()
|
||||
{
|
||||
if (AudioButtonUp)
|
||||
if(SFXPlayer.Instance) SFXPlayer.Instance.PlaySFX(AudioButtonUp, transform.position);
|
||||
ButtonUp.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class VRButtonEvent : UnityEvent<HVRButton> { }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73f686e3f59dc0541a3a83773538b43f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Tags a grabbable object as climbable which is then used by the player controller to know if they can climb or not.
|
||||
/// For the hexabody integration it will kick in the climbing strength override set on the HexaHands component.
|
||||
/// </summary>
|
||||
public class HVRClimbable : MonoBehaviour
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ff48744587821344b5cc14739c2d16c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper component used to propogate a collision if a force or velocity threshold was met.
|
||||
/// </summary>
|
||||
public class HVRCollisionEvents : MonoBehaviour
|
||||
{
|
||||
[Header("Settings")]
|
||||
|
||||
public CollisionEventType CollisionType = CollisionEventType.Impulse;
|
||||
|
||||
[Tooltip("Force threshold to breach to fire the ThresholdMet event")]
|
||||
public float ForceThreshold;
|
||||
|
||||
[Tooltip("Collision velocity threshold to breach to fire the ThresholdMetEvent")]
|
||||
public float VelocityThreshold;
|
||||
|
||||
public UnityEvent ThresholdMet = new UnityEvent();
|
||||
|
||||
[Header("Debug")]
|
||||
public float LastImpulse;
|
||||
public float LastVelocity;
|
||||
|
||||
public float MaxImpulse;
|
||||
public float MaxVelocity;
|
||||
|
||||
protected virtual void OnCollisionEnter(Collision other)
|
||||
{
|
||||
LastImpulse = other.impulse.magnitude;
|
||||
LastVelocity = other.relativeVelocity.magnitude;
|
||||
|
||||
MaxImpulse = Mathf.Max(MaxImpulse, LastImpulse);
|
||||
MaxVelocity = Mathf.Max(MaxVelocity, LastVelocity);
|
||||
|
||||
var forceMet = LastImpulse > ForceThreshold;
|
||||
var velocityMet = LastVelocity > VelocityThreshold;
|
||||
|
||||
|
||||
if (CollisionType == CollisionEventType.Impulse && forceMet ||
|
||||
CollisionType == CollisionEventType.Velocity && velocityMet ||
|
||||
CollisionType == CollisionEventType.ImpulseOrVelocity && (forceMet || velocityMet))
|
||||
{
|
||||
ThresholdMet.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public enum CollisionEventType
|
||||
{
|
||||
Impulse, Velocity, ImpulseOrVelocity
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 123d9563fca44af1864835effb36ffbc
|
||||
timeCreated: 1600399646
|
||||
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using HurricaneVR.Framework.ControllerInput;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles offsettings the physics hand target based on the connected device. Also offsets the target based on grab point settings if desired.
|
||||
/// To manage custom offsets please use the SetMiscPositionOffset(Vector3 position, Vector3 rotation) and ResetGrabPointOffsets() functions.
|
||||
/// </summary>
|
||||
public class HVRControllerOffset : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The hand that this controller offset represents.
|
||||
/// </summary>
|
||||
public HVRHandSide HandSide;
|
||||
|
||||
/// <summary>
|
||||
/// The transform that aim's the teleport line, it will be counter rotated when a grabbable requests the hand to rotate when held.
|
||||
/// </summary>
|
||||
[Tooltip("The transform that aim's the teleport line, it will be counter rotated when a grabbable requests the hand to rotate when held.")]
|
||||
public Transform Teleport;
|
||||
|
||||
/// <summary>
|
||||
/// Smooth lerp speed to move towards the target grab point rotation offset
|
||||
/// </summary>
|
||||
[Tooltip("Smooth lerp speed to move towards the target grab point rotation offset")]
|
||||
public float GrabPointSmoothSpeed = 8f;
|
||||
|
||||
private HVRDevicePoseOffset _offsets;
|
||||
|
||||
public Vector3 ControllerPositionOffset => _offsets != null ? _offsets.Position : Vector3.zero;
|
||||
public Vector3 ControllerRotationOffset => _offsets != null ? _offsets.Rotation : Vector3.zero;
|
||||
|
||||
[Header("Debugging")]
|
||||
|
||||
[Tooltip("Enable to test live updating of the Misc offset fields.")]
|
||||
public bool LiveUpdateOffsets;
|
||||
|
||||
[SerializeField] private Vector3 TargetGrabPointPositionOffset;
|
||||
[SerializeField] private Vector3 TargetGrabPointRotationOffset;
|
||||
|
||||
[SerializeField] private Vector3 GrabPointPositionOffset;
|
||||
[SerializeField] private Vector3 GrabPointRotationOffset;
|
||||
|
||||
[SerializeField] private Vector3 MiscPositionOffset;
|
||||
[SerializeField] private Vector3 MiscRotationOffset;
|
||||
|
||||
|
||||
private Quaternion _teleportStartRotation;
|
||||
|
||||
public bool _updatingRotation;
|
||||
public bool _updatingPosition;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
if (Teleport)
|
||||
{
|
||||
_teleportStartRotation = Teleport.localRotation;
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (HandSide == HVRHandSide.Left)
|
||||
{
|
||||
if (HVRInputManager.Instance.LeftController)
|
||||
ControllerConnected(HVRInputManager.Instance.LeftController);
|
||||
HVRInputManager.Instance.LeftControllerConnected.AddListener(ControllerConnected);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HVRInputManager.Instance.RightController)
|
||||
ControllerConnected(HVRInputManager.Instance.RightController);
|
||||
HVRInputManager.Instance.RightControllerConnected.AddListener(ControllerConnected);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (_updatingRotation)
|
||||
{
|
||||
GrabPointRotationOffset = Vector3.Lerp(GrabPointRotationOffset, TargetGrabPointRotationOffset, GrabPointSmoothSpeed * Time.deltaTime);
|
||||
if (Vector3.Distance(GrabPointRotationOffset, TargetGrabPointRotationOffset) < .01f)
|
||||
{
|
||||
_updatingRotation = false;
|
||||
GrabPointRotationOffset = TargetGrabPointRotationOffset;
|
||||
ApplyOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
if (_updatingPosition)
|
||||
{
|
||||
GrabPointPositionOffset = Vector3.Lerp(GrabPointPositionOffset, TargetGrabPointPositionOffset, GrabPointSmoothSpeed * Time.deltaTime);
|
||||
if (Vector3.Distance(GrabPointPositionOffset, TargetGrabPointPositionOffset) < .01f)
|
||||
{
|
||||
_updatingPosition = false;
|
||||
GrabPointPositionOffset = TargetGrabPointPositionOffset;
|
||||
ApplyOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
if (LiveUpdateOffsets || _updatingPosition || _updatingRotation)
|
||||
{
|
||||
ApplyOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMiscPositionOffset(Vector3 position, Vector3 rotation)
|
||||
{
|
||||
MiscPositionOffset = position;
|
||||
MiscRotationOffset = rotation;
|
||||
ApplyOffsets();
|
||||
}
|
||||
|
||||
|
||||
public void SetGrabPointOffsets(Vector3 position, Vector3 rotation)
|
||||
{
|
||||
TargetGrabPointPositionOffset = position;
|
||||
TargetGrabPointRotationOffset = rotation;
|
||||
_updatingRotation = true;
|
||||
_updatingPosition = true;
|
||||
}
|
||||
|
||||
public void ResetGrabPointOffsets()
|
||||
{
|
||||
TargetGrabPointPositionOffset = Vector3.zero;
|
||||
TargetGrabPointRotationOffset = Vector3.zero;
|
||||
_updatingRotation = true;
|
||||
_updatingPosition = true;
|
||||
}
|
||||
|
||||
public void ApplyOffsets()
|
||||
{
|
||||
var position = ControllerPositionOffset + GrabPointPositionOffset + MiscPositionOffset;
|
||||
|
||||
if (HandSide == HVRHandSide.Left)
|
||||
{
|
||||
position.x *= -1f;
|
||||
}
|
||||
|
||||
transform.localPosition = position;
|
||||
|
||||
var controllerRotation = Quaternion.Euler(ControllerRotationOffset);
|
||||
var grabPointRotation = Quaternion.Euler(GrabPointRotationOffset);
|
||||
var miscRotation = Quaternion.Euler(MiscRotationOffset);
|
||||
|
||||
var finalRotation = controllerRotation * grabPointRotation * miscRotation;
|
||||
var angles = finalRotation.eulerAngles;
|
||||
|
||||
if (HandSide == HVRHandSide.Left)
|
||||
{
|
||||
angles.y *= -1f;
|
||||
angles.z *= -1f;
|
||||
}
|
||||
|
||||
if (Teleport)
|
||||
{
|
||||
Teleport.localRotation = _teleportStartRotation * Quaternion.Inverse(grabPointRotation);
|
||||
}
|
||||
|
||||
transform.localEulerAngles = angles;
|
||||
}
|
||||
|
||||
private void ControllerConnected(HVRController controller)
|
||||
{
|
||||
var offsets = HVRInputManager.Instance.ControllerOffsets;
|
||||
if (!offsets)
|
||||
{
|
||||
Debug.LogWarning($"HVRInputManager.ControllerOffsets are not assigned.");
|
||||
return;
|
||||
}
|
||||
|
||||
_offsets = offsets.GetDeviceOffset(controller.Side);
|
||||
|
||||
ApplyOffsets();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59ef9bc5899042d588a09adb8a254aa9
|
||||
timeCreated: 1601145324
|
||||
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using HurricaneVR.Framework.ControllerInput;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores Unity SDK and Device offset combinations to handle the differences between SDK's and the position and rotation values they report.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "HurricaneVR/Controller Offsets", fileName = "ControllerOffset")]
|
||||
public class HVRControllerOffsets : ScriptableObject
|
||||
{
|
||||
[Header("Unity XR")]
|
||||
public HVRDevicePoseOffset Oculus;
|
||||
|
||||
public HVRDevicePoseOffset WMR;
|
||||
public HVRDevicePoseOffset Pico;
|
||||
|
||||
[Header("SteamVR")]
|
||||
public HVRDevicePoseOffset OculusSteamVR;
|
||||
|
||||
public HVRDevicePoseOffset WMRSteamVR;
|
||||
public HVRDevicePoseOffset ReverbG2SteamVR;
|
||||
public HVRDevicePoseOffset CosmosSteamVR;
|
||||
public HVRDevicePoseOffset ViveSteamVR;
|
||||
public HVRDevicePoseOffset KnucklesSteamVR;
|
||||
|
||||
[Header("OpenXR")]
|
||||
public HVRDevicePoseOffset OculusOpenXR;
|
||||
|
||||
public HVRDevicePoseOffset WMROpenXR;
|
||||
public HVRDevicePoseOffset ReverbG2OpenXR;
|
||||
public HVRDevicePoseOffset ViveOpenXR;
|
||||
public HVRDevicePoseOffset CosmosOpenXR;
|
||||
public HVRDevicePoseOffset KnucklesOpenXR;
|
||||
public HVRDevicePoseOffset PicoOpenXR;
|
||||
|
||||
public HVRDevicePoseOffset GetDeviceOffset(HVRHandSide side)
|
||||
{
|
||||
if (side == HVRHandSide.Left)
|
||||
return GetDeviceOffset(HVRInputManager.Instance.LeftController.ControllerType);
|
||||
return GetDeviceOffset(HVRInputManager.Instance.RightController.ControllerType);
|
||||
}
|
||||
|
||||
public HVRDevicePoseOffset GetDeviceOffset(HVRControllerType type)
|
||||
{
|
||||
var steamVR = HVRInputManager.Instance.IsSteamVR;
|
||||
var openXr = HVRInputManager.Instance.IsOpenXR;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HVRControllerType.Oculus:
|
||||
if (steamVR)
|
||||
{
|
||||
return OculusSteamVR;
|
||||
}
|
||||
else if (openXr)
|
||||
{
|
||||
return OculusOpenXR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Oculus;
|
||||
}
|
||||
case HVRControllerType.WMR:
|
||||
if (steamVR)
|
||||
{
|
||||
return WMRSteamVR;
|
||||
}
|
||||
else if (openXr)
|
||||
{
|
||||
return WMROpenXR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return WMR;
|
||||
}
|
||||
case HVRControllerType.Vive:
|
||||
if (steamVR)
|
||||
{
|
||||
return ViveSteamVR;
|
||||
}
|
||||
else if (openXr)
|
||||
{
|
||||
return ViveOpenXR;
|
||||
}
|
||||
|
||||
break;
|
||||
case HVRControllerType.Knuckles:
|
||||
if (steamVR)
|
||||
{
|
||||
return KnucklesSteamVR;
|
||||
}
|
||||
else if (openXr)
|
||||
{
|
||||
return KnucklesOpenXR;
|
||||
}
|
||||
|
||||
break;
|
||||
case HVRControllerType.Cosmos:
|
||||
if (steamVR)
|
||||
{
|
||||
return CosmosSteamVR;
|
||||
}
|
||||
else if (openXr)
|
||||
{
|
||||
return CosmosOpenXR;
|
||||
}
|
||||
|
||||
break;
|
||||
case HVRControllerType.ReverbG2:
|
||||
if (steamVR)
|
||||
{
|
||||
return ReverbG2SteamVR;
|
||||
}
|
||||
else if (openXr)
|
||||
{
|
||||
return ReverbG2OpenXR;
|
||||
}
|
||||
|
||||
break;
|
||||
case HVRControllerType.Pico:
|
||||
if (steamVR) //is there a way to detect pico when using steamvr? it's emulated as a oculus device
|
||||
return null;
|
||||
if (openXr)
|
||||
return PicoOpenXR;
|
||||
return Pico;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class HVRDevicePoseOffset
|
||||
{
|
||||
public Vector3 Position;
|
||||
|
||||
[FormerlySerializedAs("_rotation")]
|
||||
[SerializeField]
|
||||
public Vector3 Rotation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab72751261f74e5ebaa6986a0464cd15
|
||||
timeCreated: 1635035319
|
||||
@@ -0,0 +1,50 @@
|
||||
using HurricaneVR.Framework.Weapons;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
public class HVRDamageHandler : HVRDamageHandlerBase
|
||||
{
|
||||
public float Life = 100f;
|
||||
|
||||
public bool Damageable = true;
|
||||
|
||||
public Rigidbody Rigidbody { get; private set; }
|
||||
|
||||
public HVRDestructible Desctructible;
|
||||
|
||||
void Start()
|
||||
{
|
||||
Rigidbody = GetComponent<Rigidbody>();
|
||||
if (!Desctructible)
|
||||
Desctructible = GetComponent<HVRDestructible>();
|
||||
}
|
||||
|
||||
public override void TakeDamage(float damage)
|
||||
{
|
||||
if (Damageable)
|
||||
{
|
||||
Life -= damage;
|
||||
}
|
||||
|
||||
if (Life <= 0)
|
||||
{
|
||||
if (Desctructible)
|
||||
{
|
||||
Desctructible.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleDamageProvider(HVRDamageProvider damageProvider, Vector3 hitPoint, Vector3 direction)
|
||||
{
|
||||
base.HandleDamageProvider(damageProvider, hitPoint, direction);
|
||||
|
||||
if (Rigidbody)
|
||||
{
|
||||
Rigidbody.AddForceAtPosition(direction.normalized * damageProvider.Force, hitPoint, ForceMode.Impulse);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2fba50691c4c804ea3f345eb904cc95
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
public abstract class HVRDamageHandlerBase : MonoBehaviour
|
||||
{
|
||||
public virtual void TakeDamage(float damage)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void HandleDamageProvider(HVRDamageProvider damageProvider, Vector3 hitPoint, Vector3 direction)
|
||||
{
|
||||
TakeDamage(damageProvider.Damage);
|
||||
}
|
||||
|
||||
public virtual void HandleRayCastHit(HVRDamageProvider damageProvider, RaycastHit hit)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e49c8bf2db256ba438a090d0d46c85ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
public class HVRDamageProvider : MonoBehaviour
|
||||
{
|
||||
public float Damage = 25f;
|
||||
public float Force;
|
||||
|
||||
[Tooltip("Player transform for ai frameworks like emerald ai")]
|
||||
public Transform Player;
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 029f5fabd456e3d4ca818afd570d575d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Publishes the destroyed event so others may know, used by the hand grabber to know if the held object is destroyed
|
||||
/// </summary>
|
||||
public class HVRDestroyListener : MonoBehaviour
|
||||
{
|
||||
public HVRDestroyedEvent Destroyed = new HVRDestroyedEvent();
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Destroyed.Invoke(this);
|
||||
Destroyed.RemoveAllListeners();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class HVRDestroyedEvent : UnityEvent<HVRDestroyListener>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d73b26c803e4bbb886b5776121804b2
|
||||
timeCreated: 1600231143
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Destroys this game object after a timeout
|
||||
/// </summary>
|
||||
public class HVRDestroyTimer : MonoBehaviour
|
||||
{
|
||||
public void StartTimer(float timeout)
|
||||
{
|
||||
StartCoroutine(Cleanup(timeout));
|
||||
}
|
||||
|
||||
private IEnumerator Cleanup(float timeout)
|
||||
{
|
||||
yield return new WaitForSeconds(timeout);
|
||||
Destroy(this.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6751180565d247fba4285903a5b605aa
|
||||
timeCreated: 1601087539
|
||||
@@ -0,0 +1,75 @@
|
||||
using HurricaneVR.Framework.Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper component that spawns a prefab game object when the Destroy function is called.
|
||||
/// If the spawned game object has a rigidbodies then they will have force added to them based on the
|
||||
/// fields provided.
|
||||
/// </summary>
|
||||
public class HVRDestructible : MonoBehaviour
|
||||
{
|
||||
public GameObject DestroyedVersion;
|
||||
|
||||
public float ExplosionRadius = .1f;
|
||||
public float ExplosionPower = 1;
|
||||
public float ExplosionUpwardsPower = 1;
|
||||
|
||||
public bool RemoveDebris = true;
|
||||
public float RemoveDebrisTimerUpper = 10f;
|
||||
public float RemoveDebrisTimerLower = 5f;
|
||||
|
||||
public bool IgnorePlayerCollision = true;
|
||||
|
||||
public bool Destroyed { get; protected set; }
|
||||
|
||||
public virtual void Destroy()
|
||||
{
|
||||
if (Destroyed) return;
|
||||
|
||||
if (DestroyedVersion)
|
||||
{
|
||||
var destroyed = Instantiate(DestroyedVersion, transform.position, transform.rotation);
|
||||
|
||||
foreach (var rigidBody in destroyed.GetComponentsInChildren<Rigidbody>())
|
||||
{
|
||||
var v = new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f));
|
||||
rigidBody.AddForce(v * ExplosionPower, ForceMode.VelocityChange);
|
||||
|
||||
if (RemoveDebris)
|
||||
{
|
||||
var delay = Random.Range(RemoveDebrisTimerLower, RemoveDebrisTimerUpper);
|
||||
if (delay < .1f)
|
||||
{
|
||||
delay = 3f;
|
||||
}
|
||||
|
||||
var timer = rigidBody.gameObject.AddComponent<HVRDestroyTimer>();
|
||||
timer.StartTimer(delay);
|
||||
}
|
||||
|
||||
if (IgnorePlayerCollision)
|
||||
{
|
||||
var colliders = rigidBody.gameObject.GetComponentsInChildren<Collider>();
|
||||
HVRManager.Instance?.IgnorePlayerCollision(colliders);
|
||||
}
|
||||
|
||||
rigidBody.transform.parent = null;
|
||||
}
|
||||
|
||||
if (RemoveDebris)
|
||||
{
|
||||
var timer = destroyed.gameObject.AddComponent<HVRDestroyTimer>();
|
||||
var delay = RemoveDebrisTimerUpper;
|
||||
if (delay <= .1f)
|
||||
delay = 3f;
|
||||
timer.StartTimer(delay);
|
||||
}
|
||||
}
|
||||
|
||||
Destroyed = true;
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66f0a0ab295247a681b1b569944a2bf9
|
||||
timeCreated: 1599957568
|
||||
244
Assets/HurricaneVR/Framework/Scripts/Components/HVRDial.cs
Normal file
244
Assets/HurricaneVR/Framework/Scripts/Components/HVRDial.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.Grabbers;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Deprecated and left in for older projects. Superceded by HVRPhysicsDial and HVRRotationTracker
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(HVRGrabbable))]
|
||||
public class HVRDial : MonoBehaviour
|
||||
{
|
||||
public DialSteppedEvent DialStepChanged = new DialSteppedEvent();
|
||||
public DialTurnedEvent DialTurned = new DialTurnedEvent();
|
||||
|
||||
public Transform RotationTarget;
|
||||
public int Steps;
|
||||
public bool SnapTarget = true;
|
||||
public bool ClampMaxAngle;
|
||||
public float MaximumAngle = 360f;
|
||||
public AudioClip AudioClip;
|
||||
public float Deadzone = 1f;
|
||||
public Vector3 LocalRotationAxis;
|
||||
public Vector3 LocalAxisStart;
|
||||
public bool DiscardAngle;
|
||||
|
||||
public float StepSize;
|
||||
|
||||
private float _previousAngle;
|
||||
private Vector3 _originalVector;
|
||||
private Rigidbody _rigidBody;
|
||||
private Rigidbody _targetRigidBody;
|
||||
private float _previousAngleFromStart;
|
||||
|
||||
public int Step { get; protected set; }
|
||||
|
||||
public HVRGrabbable Grabbable { get; private set; }
|
||||
public HVRHandGrabber PrimaryGrabber { get; private set; }
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
_rigidBody = transform.GetComponent<Rigidbody>();
|
||||
_targetRigidBody = RotationTarget.GetComponent<Rigidbody>();
|
||||
|
||||
if (Steps <= 1)
|
||||
StepSize = 0f;
|
||||
else if (Steps > 1 && Mathf.Approximately(StepSize, 0f))
|
||||
StepSize = MaximumAngle / Steps;
|
||||
|
||||
LocalAxisStart.Normalize();
|
||||
LocalRotationAxis.Normalize();
|
||||
|
||||
_originalVector = transform.localRotation * LocalAxisStart;
|
||||
|
||||
Grabbable = GetComponent<HVRGrabbable>();
|
||||
Grabbable.Grabbed.AddListener(OnGrabbed);
|
||||
Grabbable.Released.AddListener(OnReleased);
|
||||
|
||||
|
||||
_previousAngle = 0f;
|
||||
_previousAngleFromStart = 0f;
|
||||
}
|
||||
|
||||
protected virtual void FixedUpdate()
|
||||
{
|
||||
//Debug.DrawLine(transform.position, transform.position + transform.TransformDirection(currentVector).normalized * 1f, Color.red);
|
||||
CheckForRotation();
|
||||
}
|
||||
|
||||
|
||||
protected void CheckForRotation(bool force = false)
|
||||
{
|
||||
if (force || PrimaryGrabber)
|
||||
{
|
||||
if (!force && Mathf.Abs(PrimaryGrabber.HVRTrackedController.DeltaEulerZ) < Deadzone)
|
||||
return;
|
||||
|
||||
var currentVector = transform.localRotation * LocalAxisStart;
|
||||
var rotationAxis = LocalRotationAxis;
|
||||
|
||||
var controllerRotation = new Vector3(
|
||||
PrimaryGrabber.HVRTrackedController.DeltaEulerZ,
|
||||
PrimaryGrabber.HVRTrackedController.DeltaEulerZ,
|
||||
PrimaryGrabber.HVRTrackedController.DeltaEulerZ);
|
||||
|
||||
controllerRotation.Scale(-rotationAxis);
|
||||
|
||||
var rotation = Quaternion.Euler(controllerRotation);
|
||||
|
||||
var newRotation = transform.localRotation * rotation;
|
||||
|
||||
var newVector = newRotation * LocalAxisStart;
|
||||
|
||||
var delta = -PrimaryGrabber.HVRTrackedController.DeltaEulerZ;
|
||||
|
||||
var angleFromStart = Vector3.SignedAngle(_originalVector, newVector, rotationAxis);
|
||||
|
||||
if (angleFromStart < 0)
|
||||
angleFromStart = 360 + angleFromStart;
|
||||
|
||||
var clockWise = delta >= 0f;
|
||||
|
||||
if (ClampMaxAngle)
|
||||
{
|
||||
|
||||
if (clockWise && _previousAngleFromStart + delta >= MaximumAngle - .1)
|
||||
{
|
||||
angleFromStart = MaximumAngle;
|
||||
}
|
||||
else if (!clockWise && _previousAngleFromStart + delta <= 0.1)
|
||||
{
|
||||
angleFromStart = 0;
|
||||
}
|
||||
else if (angleFromStart > MaximumAngle)
|
||||
{
|
||||
float upDiff = 360 - angleFromStart;
|
||||
float lowerDiff = angleFromStart - MaximumAngle;
|
||||
|
||||
if (upDiff < lowerDiff) angleFromStart = 0;
|
||||
else angleFromStart = MaximumAngle;
|
||||
}
|
||||
}
|
||||
|
||||
var stepAngle = angleFromStart;
|
||||
if (Steps > 1)
|
||||
{
|
||||
Step = Mathf.RoundToInt(angleFromStart / StepSize);
|
||||
stepAngle = Step * StepSize;
|
||||
if (Mathf.Approximately(stepAngle, 360))
|
||||
{
|
||||
Step = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var finalVector = Quaternion.AngleAxis(angleFromStart, rotationAxis) * _originalVector;
|
||||
var syncAngle = Vector3.SignedAngle(currentVector, finalVector, rotationAxis);
|
||||
var syncRotation = Quaternion.AngleAxis(syncAngle, rotationAxis) * transform.localRotation;
|
||||
|
||||
if (Steps > 1)
|
||||
{
|
||||
if (!Mathf.Approximately(stepAngle, _previousAngle))
|
||||
{
|
||||
OnStepChanged(Step, true);
|
||||
_previousAngle = stepAngle;
|
||||
|
||||
if (SnapTarget)
|
||||
{
|
||||
var percent = Mathf.Approximately(0f, MaximumAngle) ? 0f : stepAngle / MaximumAngle;
|
||||
OnAngleChanged(stepAngle, syncAngle, percent, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SnapTarget && !Mathf.Approximately(_previousAngleFromStart, angleFromStart))
|
||||
{
|
||||
var percent = Mathf.Approximately(0f, MaximumAngle) ? 0f : angleFromStart / MaximumAngle;
|
||||
OnAngleChanged(angleFromStart, syncAngle, angleFromStart / percent, true);
|
||||
}
|
||||
|
||||
var steppedVector = Quaternion.AngleAxis(stepAngle, rotationAxis) * _originalVector;
|
||||
var steppedAngle = Vector3.SignedAngle(currentVector, steppedVector, rotationAxis);
|
||||
var steppedRotation = Quaternion.AngleAxis(steppedAngle, rotationAxis) * transform.localRotation;
|
||||
|
||||
var targetRotation = SnapTarget ? steppedRotation : syncRotation;
|
||||
|
||||
//if (_targetRigidBody)
|
||||
//{
|
||||
// _targetRigidBody.MoveRotation(_targetRigidBody.rotation * targetRotation);
|
||||
//}
|
||||
//else
|
||||
{
|
||||
RotationTarget.localRotation = targetRotation;
|
||||
}
|
||||
|
||||
//if (_rigidBody)
|
||||
//{
|
||||
// _rigidBody.MoveRotation(_rigidBody.rotation * syncRotation);
|
||||
//}
|
||||
//else
|
||||
{
|
||||
transform.localRotation = syncRotation;
|
||||
}
|
||||
|
||||
_previousAngleFromStart = angleFromStart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected void OnGrabbed(HVRGrabberBase grabber, HVRGrabbable hvrGrabbable)
|
||||
{
|
||||
PrimaryGrabber = grabber as HVRHandGrabber;
|
||||
|
||||
if (DiscardAngle)
|
||||
{
|
||||
if (_rigidBody)
|
||||
{
|
||||
_rigidBody.MoveRotation(RotationTarget.rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.localRotation = RotationTarget.localRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnReleased(HVRGrabberBase grabber, HVRGrabbable hvrGrabbable)
|
||||
{
|
||||
PrimaryGrabber = null;
|
||||
|
||||
if (DiscardAngle)
|
||||
{
|
||||
if (_rigidBody)
|
||||
{
|
||||
_rigidBody.MoveRotation(RotationTarget.rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.localRotation = RotationTarget.localRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnStepChanged(int step, bool raiseEvents)
|
||||
{
|
||||
if (AudioClip)
|
||||
if(SFXPlayer.Instance) SFXPlayer.Instance.PlaySFXRandomPitch(AudioClip, transform.position, .9f, 1.1f);
|
||||
if (raiseEvents)
|
||||
DialStepChanged.Invoke(step);
|
||||
}
|
||||
|
||||
protected virtual void OnAngleChanged(float angle, float delta, float percent, bool raiseEvents)
|
||||
{
|
||||
if (raiseEvents)
|
||||
DialTurned.Invoke(angle, delta, percent);
|
||||
}
|
||||
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a95f97577cc01a746a9d0a3e11b90b8c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
public class HVRDontDestroy : MonoBehaviour
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e5b279a1a044cee9d64e0ca5d85f175
|
||||
timeCreated: 1601039791
|
||||
@@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
public abstract class HVRGrabbableHoverBase : MonoBehaviour
|
||||
{
|
||||
public HVRHoverPosition HoverPosition = HVRHoverPosition.GrabPoint;
|
||||
public bool LookAtCamera = true;
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public abstract void Hover();
|
||||
|
||||
public abstract void Unhover();
|
||||
|
||||
public abstract void Enable();
|
||||
public abstract void Disable();
|
||||
}
|
||||
|
||||
public enum HVRHoverPosition
|
||||
{
|
||||
GrabPoint,
|
||||
Self,
|
||||
Transform
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c25cecd1cd34cd7a4346c955a0add93
|
||||
timeCreated: 1600204770
|
||||
@@ -0,0 +1,28 @@
|
||||
using HurricaneVR.Framework.Core;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
|
||||
public class HVRGrabbableImpactHaptics : HVRImpactHapticsBase
|
||||
{
|
||||
public HVRGrabbable Grabbable;
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
if (!Grabbable) TryGetComponent(out Grabbable);
|
||||
}
|
||||
|
||||
protected override void Vibrate(float duration, float amplitude, float frequency)
|
||||
{
|
||||
for (var i = 0; i < Grabbable.HandGrabbers.Count; i++)
|
||||
{
|
||||
var h = Grabbable.HandGrabbers[i];
|
||||
if (!h.IsMine) break;
|
||||
|
||||
h.Controller.Vibrate(amplitude, Data.Duration, Data.Frequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77dbe74f0338a6c438b0af580dd1253e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
using HurricaneVR.Framework.Core.Grabbers;
|
||||
using HurricaneVR.Framework.Core.Player;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
public class HVRHandImpactHaptics : HVRImpactHapticsBase
|
||||
{
|
||||
public HVRHandGrabber Hand;
|
||||
|
||||
[Tooltip("If true and the hand is holding something, haptics will not play.")]
|
||||
public bool HandGrabbingPrevents = true;
|
||||
|
||||
[Tooltip("If true the max force for the haptic amplitude calc will use the hand's default max force.")]
|
||||
public bool UseHandMaxStrength = true;
|
||||
|
||||
private HVRJointHand _hand;
|
||||
|
||||
public override float MaxForce
|
||||
{
|
||||
get
|
||||
{
|
||||
if (UseHandMaxStrength)
|
||||
{
|
||||
if ( _hand && _hand.JointSettings)
|
||||
return _hand.JointSettings.XDrive.MaxForce;
|
||||
}
|
||||
|
||||
return base.MaxForce;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
if (!Hand) TryGetComponent(out Hand);
|
||||
|
||||
TryGetComponent(out _hand);
|
||||
}
|
||||
|
||||
protected override void Vibrate(float duration, float amplitude, float frequency)
|
||||
{
|
||||
if (HandGrabbingPrevents && Hand.IsGrabbing) return;
|
||||
Hand.Controller.Vibrate(amplitude, duration, frequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 735256ec9b08e024a8efea6924dd44b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.HandPoser;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
using UnityEngine.InputSystem;
|
||||
#endif
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
public class HVRHandPoseRecorder : MonoBehaviour
|
||||
{
|
||||
#if ENABLE_LEGACY_INPUT_MANAGER
|
||||
public KeyCode LeftHandSaveKey = KeyCode.L;
|
||||
public KeyCode RightHandSaveKey = KeyCode.R;
|
||||
#endif
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
|
||||
public Key LeftSaveKey = Key.L;
|
||||
public Key RightSaveKey = Key.R;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
public HVRPosableHand LeftHand;
|
||||
public HVRPosableHand RightHand;
|
||||
|
||||
public HVRHandPhysics LeftPhysics;
|
||||
public HVRHandPhysics RightPhysics;
|
||||
|
||||
public float FadeTimer = 10f;
|
||||
public bool RemoveClones = true;
|
||||
|
||||
public bool DisablePhysics;
|
||||
|
||||
private bool _previousDisable;
|
||||
|
||||
public string Folder;
|
||||
public int Counter = 0;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Folder = DateTime.Now.ToString("yyyyMMdd_HH_mm");
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
void Update()
|
||||
{
|
||||
|
||||
|
||||
if (DisablePhysics && !_previousDisable)
|
||||
{
|
||||
if (LeftPhysics)
|
||||
{
|
||||
LeftPhysics.DisableCollision();
|
||||
}
|
||||
|
||||
if (RightPhysics)
|
||||
{
|
||||
RightPhysics.DisableCollision();
|
||||
}
|
||||
}
|
||||
else if (!DisablePhysics && _previousDisable)
|
||||
{
|
||||
if (LeftPhysics)
|
||||
{
|
||||
LeftPhysics.EnableCollision();
|
||||
}
|
||||
|
||||
if (RightPhysics)
|
||||
{
|
||||
RightPhysics.EnableCollision();
|
||||
}
|
||||
}
|
||||
|
||||
_previousDisable = DisablePhysics;
|
||||
|
||||
CheckSnapshot();
|
||||
|
||||
}
|
||||
#endif
|
||||
private void CheckSnapshot()
|
||||
{
|
||||
HVRPosableHand hand = null;
|
||||
|
||||
#if ENABLE_LEGACY_INPUT_MANAGER
|
||||
if (Input.GetKeyDown(LeftHandSaveKey))
|
||||
{
|
||||
hand = LeftHand;
|
||||
}
|
||||
else if (Input.GetKeyDown(RightHandSaveKey))
|
||||
{
|
||||
hand = RightHand;
|
||||
}
|
||||
else
|
||||
return;
|
||||
#elif ENABLE_INPUT_SYSTEM
|
||||
|
||||
if (Keyboard.current[LeftSaveKey].wasPressedThisFrame)
|
||||
{
|
||||
hand = LeftHand;
|
||||
}
|
||||
else if (Keyboard.current[RightSaveKey].wasPressedThisFrame)
|
||||
{
|
||||
hand = RightHand;
|
||||
}
|
||||
else
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!hand)
|
||||
return;
|
||||
|
||||
Snapshot(hand);
|
||||
}
|
||||
|
||||
public void SnapshotLeft()
|
||||
{
|
||||
if (!gameObject.activeSelf)
|
||||
return;
|
||||
if (LeftHand)
|
||||
{
|
||||
Snapshot(LeftHand);
|
||||
}
|
||||
}
|
||||
|
||||
public void SnapshotRight()
|
||||
{
|
||||
if (!gameObject.activeSelf)
|
||||
return;
|
||||
|
||||
if (RightHand)
|
||||
{
|
||||
Snapshot(RightHand);
|
||||
}
|
||||
}
|
||||
|
||||
private void Snapshot(HVRPosableHand hand)
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
var pose = hand.CreateFullHandPoseWorld(hand.MirrorAxis);
|
||||
|
||||
HVRSettings.Instance.SaveRunTimePose(pose, Counter++.ToString(), Folder);
|
||||
|
||||
var clone = Instantiate(HVRSettings.Instance.GetPoserHand(hand.Side));
|
||||
|
||||
var posableHand = clone.GetComponent<HVRPosableHand>();
|
||||
if (posableHand != null)
|
||||
{
|
||||
posableHand.Pose(pose.GetPose(hand.Side));
|
||||
clone.transform.position = hand.transform.position;
|
||||
clone.transform.rotation = hand.transform.rotation;
|
||||
}
|
||||
|
||||
var colliders = clone.GetComponentsInChildren<Collider>();
|
||||
foreach (var c in colliders)
|
||||
{
|
||||
c.enabled = false;
|
||||
}
|
||||
|
||||
if (RemoveClones)
|
||||
{
|
||||
StartCoroutine(RemoveClone(clone));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public IEnumerator RemoveClone(GameObject clone)
|
||||
{
|
||||
yield return new WaitForSeconds(FadeTimer);
|
||||
Destroy(clone);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60ac0a61a75ecf64e8c54dcb82a08821
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
|
||||
[CreateAssetMenu(menuName = "HurricaneVR/Impact Haptics", fileName = "ImpactHaptics")]
|
||||
public class HVRImpactHaptics : ScriptableObject
|
||||
{
|
||||
public float Timeout = .3f;
|
||||
|
||||
[Tooltip("Collision Velocity Square Magnitude cut off filter")]
|
||||
public float SqrMagThreshold = .30f;
|
||||
|
||||
[Tooltip("Collision force divided by this and fed into the AmpCurve. ")]
|
||||
public float MaxForce = 300f;
|
||||
|
||||
public AnimationCurve AmpCurve;
|
||||
|
||||
[Tooltip("Duration fed into haptics API.")]
|
||||
public float Duration = .25f;
|
||||
|
||||
[Tooltip("Frequency fed into haptics API")]
|
||||
public float Frequency = 150f;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Frequency = 150f;
|
||||
Duration = .25f;
|
||||
MaxForce = 600f;
|
||||
SqrMagThreshold = .30f;
|
||||
Timeout = .3f;
|
||||
|
||||
AmpCurve = new AnimationCurve(new Keyframe(0f, .35f, 0f, 0f, 0f, 0f)
|
||||
{
|
||||
weightedMode = WeightedMode.None
|
||||
}, new Keyframe(1f, 1f, 2f, 2f, 0f, 0f)
|
||||
{
|
||||
weightedMode = WeightedMode.None
|
||||
});
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
//unity bugged Reset conext menu on some versions
|
||||
[MenuItem("CONTEXT/ImpactHaptics/Reset (Custom)")]
|
||||
static void CReset(MenuCommand command)
|
||||
{
|
||||
(command.context as HVRImpactHaptics)?.Reset();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b775075551dfdd947bebcfce71c1a7c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.Grabbers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
public abstract class HVRImpactHapticsBase : MonoBehaviour
|
||||
{
|
||||
public HVRImpactHaptics Data;
|
||||
|
||||
[Header("Debug")]
|
||||
public float Force;
|
||||
|
||||
private float _lastHaptic;
|
||||
private Rigidbody Rb;
|
||||
|
||||
public virtual float MaxForce => Data.MaxForce;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
TryGetComponent(out Rb);
|
||||
|
||||
if (!Data)
|
||||
{
|
||||
Data = ScriptableObject.CreateInstance<HVRImpactHaptics>();
|
||||
Data.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnCollisionEnter(Collision other)
|
||||
{
|
||||
if (!Rb) TryGetComponent(out Rb);
|
||||
|
||||
if (!Rb || Rb.velocity.sqrMagnitude < Data.SqrMagThreshold)
|
||||
return;
|
||||
|
||||
if (Time.realtimeSinceStartup - _lastHaptic < Data.Timeout)
|
||||
return;
|
||||
|
||||
float impulse;
|
||||
|
||||
if (other.impulse.sqrMagnitude > 0f)
|
||||
{
|
||||
impulse = other.impulse.magnitude;
|
||||
}
|
||||
else
|
||||
{
|
||||
impulse = other.relativeVelocity.magnitude * Rb.mass;
|
||||
}
|
||||
|
||||
Force = impulse / Time.fixedDeltaTime;
|
||||
|
||||
var amp = Data.AmpCurve.Evaluate(Force / MaxForce);
|
||||
|
||||
Vibrate(Data.Duration, amp, Data.Frequency);
|
||||
|
||||
_lastHaptic = Time.realtimeSinceStartup;
|
||||
}
|
||||
|
||||
protected virtual void Vibrate(float duration, float amplitude, float frequency)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38a18e75cd9699f428ac9902c039394c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
246
Assets/HurricaneVR/Framework/Scripts/Components/HVRLever.cs
Normal file
246
Assets/HurricaneVR/Framework/Scripts/Components/HVRLever.cs
Normal file
@@ -0,0 +1,246 @@
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.Grabbers;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Depecrecated and left in for older projects, superceded by HVRPhysicsLever and HVRRotationTracker
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(HVRGrabbable))]
|
||||
[RequireComponent(typeof(HingeJoint))]
|
||||
public class HVRLever : MonoBehaviour
|
||||
{
|
||||
[Header("Transforms")]
|
||||
[Tooltip("Target transform to rotate if the visual handle is not this object")]
|
||||
public Transform RotationTarget;
|
||||
|
||||
[Tooltip("Used to track the delta angle change, use with TrackerAxis.")]
|
||||
public Transform Tracker;
|
||||
|
||||
[Header("Settings")]
|
||||
|
||||
[Tooltip("When the lever is released with Snap mode, should the grabbable handle snap to the RotationTarget")]
|
||||
public bool DiscardAngle;
|
||||
|
||||
[Tooltip("Amount of steps the lever will click")]
|
||||
public int Steps;
|
||||
|
||||
[Tooltip("Rotation Target snaps to the step angle size")]
|
||||
public bool SnapTarget = true;
|
||||
|
||||
[Tooltip("Angle offset the lever starts in relation to LocalAxisStart field")]
|
||||
public float Offset;
|
||||
|
||||
[Tooltip("Vector of the starting 0 angle of the lever.")]
|
||||
public Vector3 LocalAxisStart;
|
||||
[Tooltip("Choose an axis that isn't the same as the hinge axis")]
|
||||
public Vector3 TrackerAxis = new Vector3(0, 1, 0);
|
||||
|
||||
|
||||
[Tooltip("SFX to play whenever the lever snaps")]
|
||||
public AudioClip AudioClip;
|
||||
|
||||
protected HingeJoint HingeJoint;
|
||||
|
||||
[Header("Debug")]
|
||||
public float MinAngle;
|
||||
public float MaxAngle;
|
||||
public Vector3 LocalRotationAxis;
|
||||
public float StepSize;
|
||||
public int CurrentStep;
|
||||
public float CurrentAngle;
|
||||
|
||||
public LeverMovedEvent Moved = new LeverMovedEvent();
|
||||
public LeverSteppedEvent Stepped = new LeverSteppedEvent();
|
||||
|
||||
private float _previousAngle;
|
||||
private Vector3 _previousVector;
|
||||
private Vector3 _originalVector;
|
||||
private float _previousAngleFromStart;
|
||||
|
||||
public HVRGrabbable Grabbable { get; private set; }
|
||||
public Rigidbody Rigidbody => Grabbable.Rigidbody;
|
||||
public HVRGrabberBase PrimaryGrabber => Grabbable.PrimaryGrabber;
|
||||
|
||||
public float Range { get; set; }
|
||||
|
||||
protected void Start()
|
||||
{
|
||||
if (!RotationTarget)
|
||||
RotationTarget = transform;
|
||||
|
||||
Grabbable = GetComponent<HVRGrabbable>();
|
||||
|
||||
HingeJoint = GetComponent<HingeJoint>();
|
||||
|
||||
MinAngle = HingeJoint.limits.min;
|
||||
MaxAngle = HingeJoint.limits.max;
|
||||
|
||||
Range = MaxAngle - MinAngle;
|
||||
|
||||
LocalRotationAxis = HingeJoint.axis;
|
||||
|
||||
if (Steps <= 1)
|
||||
{
|
||||
StepSize = 0f;
|
||||
}
|
||||
else if (Steps > 1 && Mathf.Approximately(StepSize, 0f))
|
||||
{
|
||||
StepSize = Range / Steps;
|
||||
}
|
||||
|
||||
_originalVector = transform.TransformDirection(LocalAxisStart);
|
||||
|
||||
_previousVector = LocalAxisStart;
|
||||
|
||||
SetupStartRotation();
|
||||
|
||||
transform.rotation = RotationTarget.rotation;
|
||||
|
||||
Grabbable.Grabbed.AddListener(OnGrabbed);
|
||||
Grabbable.Released.AddListener(OnReleased);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void FixedUpdate()
|
||||
{
|
||||
CheckForRotation();
|
||||
}
|
||||
|
||||
private void CheckForRotation(bool force = false)
|
||||
{
|
||||
if (!force && Rigidbody.isKinematic && !PrimaryGrabber)
|
||||
return;
|
||||
|
||||
var currentVector = Tracker.TransformDirection(TrackerAxis);
|
||||
var worldRotationAxis = transform.TransformDirection(LocalRotationAxis);
|
||||
|
||||
var angleFromStart = Vector3.SignedAngle(_originalVector, currentVector, worldRotationAxis);
|
||||
angleFromStart += Offset;
|
||||
if ((int)angleFromStart < 0)
|
||||
angleFromStart = 360 + angleFromStart;
|
||||
|
||||
var deltaAngle = Vector3.SignedAngle(_previousVector, currentVector, worldRotationAxis);
|
||||
|
||||
CurrentAngle = angleFromStart;
|
||||
var stepAngle = angleFromStart;
|
||||
if (Steps > 1)
|
||||
{
|
||||
CurrentStep = Mathf.RoundToInt(angleFromStart / StepSize);
|
||||
stepAngle = CurrentStep * StepSize;
|
||||
|
||||
if (!Mathf.Approximately(stepAngle, _previousAngle))
|
||||
{
|
||||
OnStepChanged(CurrentStep);
|
||||
_previousAngle = stepAngle;
|
||||
|
||||
if (SnapTarget)
|
||||
{
|
||||
var percent = Mathf.Approximately(0f, Range) ? 0f : stepAngle / Range;
|
||||
OnAngleChanged(stepAngle, deltaAngle, percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_previousVector = currentVector;
|
||||
|
||||
var steppedVector = Quaternion.AngleAxis(stepAngle - Offset, worldRotationAxis) * _originalVector;
|
||||
var steppedAngle = Vector3.SignedAngle(currentVector, steppedVector, worldRotationAxis);
|
||||
var steppedRotation = Quaternion.AngleAxis(steppedAngle, worldRotationAxis) * transform.rotation;
|
||||
|
||||
if (!SnapTarget && !Mathf.Approximately(_previousAngleFromStart, angleFromStart))
|
||||
{
|
||||
var percent = Mathf.Approximately(0f, Range) ? 0f : angleFromStart / Range;
|
||||
OnAngleChanged(angleFromStart, deltaAngle, percent);
|
||||
}
|
||||
|
||||
if (SnapTarget)
|
||||
{
|
||||
RotationTarget.rotation = steppedRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
RotationTarget.rotation = transform.rotation;
|
||||
}
|
||||
|
||||
_previousAngleFromStart = angleFromStart;
|
||||
}
|
||||
|
||||
private void SetupStartRotation()
|
||||
{
|
||||
var currentVector = transform.TransformDirection(TrackerAxis);
|
||||
var worldRotationAxis = transform.TransformDirection(LocalRotationAxis);
|
||||
|
||||
var angleFromStart = Vector3.SignedAngle(_originalVector, currentVector, worldRotationAxis);
|
||||
angleFromStart += Offset;
|
||||
if ((int)angleFromStart < 0)
|
||||
angleFromStart = 360 + angleFromStart;
|
||||
|
||||
CurrentAngle = angleFromStart;
|
||||
var stepAngle = angleFromStart;
|
||||
if (Steps > 1)
|
||||
{
|
||||
CurrentStep = Mathf.RoundToInt(angleFromStart / StepSize);
|
||||
stepAngle = CurrentStep * StepSize;
|
||||
|
||||
if (!Mathf.Approximately(stepAngle, _previousAngle))
|
||||
{
|
||||
_previousAngle = stepAngle;
|
||||
}
|
||||
}
|
||||
|
||||
_previousVector = currentVector;
|
||||
|
||||
var steppedVector = Quaternion.AngleAxis(stepAngle - Offset, worldRotationAxis) * _originalVector;
|
||||
var steppedAngle = Vector3.SignedAngle(currentVector, steppedVector, worldRotationAxis);
|
||||
var steppedRotation = Quaternion.AngleAxis(steppedAngle, worldRotationAxis) * transform.rotation;
|
||||
|
||||
if (SnapTarget)
|
||||
{
|
||||
RotationTarget.rotation = steppedRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
RotationTarget.rotation = transform.rotation;
|
||||
}
|
||||
|
||||
_previousAngleFromStart = angleFromStart;
|
||||
}
|
||||
|
||||
protected void OnGrabbed(HVRGrabberBase grabber, HVRGrabbable hvrGrabbable)
|
||||
{
|
||||
if (DiscardAngle)
|
||||
{
|
||||
transform.rotation = RotationTarget.rotation;
|
||||
transform.position = RotationTarget.position;
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnReleased(HVRGrabberBase grabber, HVRGrabbable hvrGrabbable)
|
||||
{
|
||||
if (DiscardAngle)
|
||||
{
|
||||
transform.rotation = RotationTarget.rotation;
|
||||
transform.position = RotationTarget.position;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnStepChanged(int step, bool raiseEvents = true)
|
||||
{
|
||||
if (AudioClip)
|
||||
if(SFXPlayer.Instance) SFXPlayer.Instance.PlaySFXRandomPitch(AudioClip, transform.position, .9f, 1.1f);
|
||||
if (raiseEvents)
|
||||
Stepped.Invoke(step);
|
||||
}
|
||||
|
||||
protected virtual void OnAngleChanged(float angle, float delta, float percent, bool raiseEvents = true)
|
||||
{
|
||||
if (raiseEvents)
|
||||
Moved.Invoke(angle, delta, percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e395cf0cf494656baa6b1eddceceb24
|
||||
timeCreated: 1600542387
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
public class HVRMeshGlowHighlight : HVRGrabbableHoverBase
|
||||
{
|
||||
private readonly HashSet<GameObject> _highlightObjects = new HashSet<GameObject>();
|
||||
private readonly HashSet<MeshRenderer> _renderers = new HashSet<MeshRenderer>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
var meshes = GetComponentsInChildren<MeshFilter>();
|
||||
|
||||
foreach (var mesh in meshes)
|
||||
{
|
||||
var go = mesh.gameObject;
|
||||
var meshRenderer = go.GetComponent<MeshRenderer>();
|
||||
if (meshRenderer)
|
||||
{
|
||||
_renderers.Add(meshRenderer);
|
||||
}
|
||||
var highlightObj = new GameObject("HighlightMesh");
|
||||
highlightObj.transform.SetParent(go.transform, false);
|
||||
|
||||
var clone = highlightObj.AddComponent<MeshFilter>();
|
||||
clone.sharedMesh = mesh.sharedMesh;
|
||||
var newRenderer = highlightObj.AddComponent<MeshRenderer>();
|
||||
newRenderer.sharedMaterial = Resources.Load<Material>("GrabbableHighlight");
|
||||
|
||||
_highlightObjects.Add(highlightObj);
|
||||
highlightObj.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Hover()
|
||||
{
|
||||
foreach (var highlight in _highlightObjects)
|
||||
{
|
||||
highlight.SetActive(true);
|
||||
}
|
||||
|
||||
foreach (var r in _renderers)
|
||||
{
|
||||
r.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Unhover()
|
||||
{
|
||||
foreach (var highlight in _highlightObjects)
|
||||
{
|
||||
highlight.SetActive(false);
|
||||
}
|
||||
|
||||
foreach (var r in _renderers)
|
||||
{
|
||||
r.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e7c9a97934caec4897562447669e7e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
[RequireComponent(typeof(MeshRenderer))]
|
||||
public class HVRMeshRendererHighlight : HVRGrabbableHoverBase
|
||||
{
|
||||
public MeshRenderer Renderer { get; private set; }
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
Renderer = GetComponent<MeshRenderer>();
|
||||
|
||||
}
|
||||
|
||||
public override void Hover()
|
||||
{
|
||||
Renderer.enabled = true;
|
||||
}
|
||||
|
||||
public override void Unhover()
|
||||
{
|
||||
Renderer.enabled = false;
|
||||
}
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
Renderer.enabled = true;
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
Renderer.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86ae87a96c3b7dd4c8c15912e79812f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper component to parent this transform to the assigned transform on game start
|
||||
/// </summary>
|
||||
public class HVRParentOnStart : MonoBehaviour
|
||||
{
|
||||
public Transform Parent;
|
||||
public bool WorldPositionStays = true;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (Parent)
|
||||
{
|
||||
transform.SetParent(Parent, WorldPositionStays);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b06dd533ee37487db0603f3b328f972f
|
||||
timeCreated: 1602523768
|
||||
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using HurricaneVR.Framework.Core.ScriptableObjects;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a joint constrained along one axis with limits based on start and end points defined in the inspector editor.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public class HVRPhysicsButton : MonoBehaviour
|
||||
{
|
||||
[Header("Settings")]
|
||||
|
||||
[Tooltip("Axis the button will travel on in local space.")]
|
||||
public HVRAxis Axis;
|
||||
|
||||
[Tooltip("Rigidbody this button will connect to with a joint.")]
|
||||
public Rigidbody ConnectedBody;
|
||||
|
||||
[Tooltip("Spring value of the joint")]
|
||||
public float Spring = 1000f;
|
||||
|
||||
[Tooltip("Damper of the joint")]
|
||||
public float Damper = 50f;
|
||||
|
||||
|
||||
|
||||
[Header("Button Positions")]
|
||||
[Tooltip("How far the button must travel to become pressed.")]
|
||||
public float DownThreshold;
|
||||
|
||||
[Tooltip("Threshold to hit on the return to allow the button to be pressed again.")]
|
||||
public float ResetThreshold;
|
||||
|
||||
[Tooltip("The resting position of the button")]
|
||||
public Vector3 StartPosition;
|
||||
|
||||
[Tooltip("Furthest position the button can travel")]
|
||||
public Vector3 EndPosition;
|
||||
|
||||
|
||||
|
||||
[Header("SFX")]
|
||||
public AudioClip SFXButtonDown;
|
||||
public AudioClip SFXButtonUp;
|
||||
|
||||
public HVRButtonEvent ButtonDown = new HVRButtonEvent();
|
||||
public HVRButtonEvent ButtonUp = new HVRButtonEvent();
|
||||
|
||||
[Header("Debug")]
|
||||
public bool IsPressed = false;
|
||||
public bool InvokeButtonDown;
|
||||
public bool UpdateSpring;
|
||||
|
||||
public Rigidbody Rigidbody { get; private set; }
|
||||
|
||||
private Vector3 _axis;
|
||||
private ConfigurableJoint _joint;
|
||||
private ConfigurableJoint _limitJoint;
|
||||
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
transform.localPosition = StartPosition;
|
||||
Rigidbody = GetComponent<Rigidbody>();
|
||||
_axis = Axis.GetVector();
|
||||
Rigidbody.useGravity = false;
|
||||
SetupJoint();
|
||||
}
|
||||
|
||||
private void SetupJoint()
|
||||
{
|
||||
var worldStartPosition = StartPosition;
|
||||
if (transform.parent)
|
||||
worldStartPosition = transform.parent.TransformPoint(StartPosition);
|
||||
|
||||
var worldEndPosition = EndPosition;
|
||||
if (transform.parent)
|
||||
worldEndPosition = transform.parent.TransformPoint(EndPosition);
|
||||
|
||||
_joint = gameObject.AddComponent<ConfigurableJoint>();
|
||||
_joint.autoConfigureConnectedAnchor = false;
|
||||
_joint.connectedBody = ConnectedBody;
|
||||
_joint.anchor = Vector3.zero;
|
||||
|
||||
|
||||
|
||||
if (ConnectedBody)
|
||||
{
|
||||
_joint.connectedAnchor = ConnectedBody.transform.InverseTransformPoint(worldStartPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
_joint.connectedAnchor = worldStartPosition;
|
||||
}
|
||||
|
||||
_joint.SetXDrive(Spring, Damper, Spring);
|
||||
|
||||
_joint.LimitXMotion();
|
||||
_joint.LockYMotion();
|
||||
_joint.LockZMotion();
|
||||
_joint.LockAllAngularMotion();
|
||||
_joint.axis = _axis;
|
||||
_joint.secondaryAxis = _joint.axis.OrthogonalVector();
|
||||
_joint.SetLinearLimit(Vector3.Distance(StartPosition, EndPosition));
|
||||
|
||||
_limitJoint = gameObject.AddComponent<ConfigurableJoint>();
|
||||
_limitJoint.autoConfigureConnectedAnchor = false;
|
||||
_limitJoint.connectedBody = ConnectedBody;
|
||||
_limitJoint.anchor = Vector3.zero;
|
||||
|
||||
|
||||
if (ConnectedBody)
|
||||
{
|
||||
_limitJoint.connectedAnchor = ConnectedBody.transform.InverseTransformPoint(worldEndPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
_limitJoint.connectedAnchor = worldEndPosition;
|
||||
}
|
||||
|
||||
_limitJoint.LockYMotion();
|
||||
_limitJoint.LockZMotion();
|
||||
_limitJoint.LockAllAngularMotion();
|
||||
_limitJoint.axis = _axis;
|
||||
_limitJoint.secondaryAxis = _joint.axis.OrthogonalVector();
|
||||
_limitJoint.LimitXMotion();
|
||||
_limitJoint.SetLinearLimit(Vector3.Distance(StartPosition, EndPosition));
|
||||
}
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (UpdateSpring)
|
||||
{
|
||||
_joint.SetXDrive(Spring, Damper, Spring);
|
||||
UpdateSpring = false;
|
||||
}
|
||||
|
||||
var distance = Mathf.Abs(GetDistance());
|
||||
|
||||
if (!IsPressed && distance >= DownThreshold || InvokeButtonDown)
|
||||
{
|
||||
InvokeButtonDown = false;
|
||||
IsPressed = true;
|
||||
OnButtonDown();
|
||||
}
|
||||
else if (IsPressed && distance < ResetThreshold)
|
||||
{
|
||||
IsPressed = false;
|
||||
OnButtonUp();
|
||||
}
|
||||
}
|
||||
|
||||
private float GetDistance()
|
||||
{
|
||||
switch (Axis)
|
||||
{
|
||||
case HVRAxis.X:
|
||||
case HVRAxis.NegX:
|
||||
return transform.localPosition.x - StartPosition.x;
|
||||
case HVRAxis.Y:
|
||||
case HVRAxis.NegY:
|
||||
return transform.localPosition.y - StartPosition.y;
|
||||
case HVRAxis.Z:
|
||||
case HVRAxis.NegZ:
|
||||
return transform.localPosition.z - StartPosition.z;
|
||||
}
|
||||
|
||||
return 0f;
|
||||
}
|
||||
|
||||
protected virtual void OnButtonDown()
|
||||
{
|
||||
if (SFXButtonDown)
|
||||
{
|
||||
if(SFXPlayer.Instance) SFXPlayer.Instance.PlaySFX(SFXButtonDown, transform.position);
|
||||
}
|
||||
|
||||
ButtonDown.Invoke(this);
|
||||
}
|
||||
|
||||
protected virtual void OnButtonUp()
|
||||
{
|
||||
if (SFXButtonUp)
|
||||
{
|
||||
if(SFXPlayer.Instance) SFXPlayer.Instance.PlaySFX(SFXButtonUp, transform.position);
|
||||
}
|
||||
ButtonUp.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class HVRButtonEvent : UnityEvent<HVRPhysicsButton> { }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fb388898ff2f814f84c5cfa8b56235f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,188 @@
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.Grabbers;
|
||||
using HurricaneVR.Framework.Core.ScriptableObjects;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple component to help setup a joint constrained on one axis. With bonus rotation friction option when held.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public class HVRPhysicsDial : MonoBehaviour
|
||||
{
|
||||
[Header("Settings")]
|
||||
[Tooltip("Local axis of rotation")]
|
||||
public HVRAxis Axis;
|
||||
|
||||
[Tooltip("Rigidbody to connect the joint to")]
|
||||
public Rigidbody ConnectedBody;
|
||||
|
||||
[Tooltip("If true the angular velocity will be zero'd out on release.")]
|
||||
public bool StopOnRelease = true;
|
||||
|
||||
[Tooltip("Defaults to true to prevent rotation when not held")]
|
||||
public bool DisableGravity = true;
|
||||
|
||||
[Header("Joint Limits")]
|
||||
public bool LimitRotation;
|
||||
|
||||
[Tooltip("Minimum Angle about the axis of rotation")]
|
||||
public float MinAngle;
|
||||
|
||||
[Tooltip("Maximum rotation about the axis of rotation")]
|
||||
public float MaxAngle;
|
||||
|
||||
[Header("Joint Settings")]
|
||||
[Tooltip("Angular Damper when the dial is grabbed")]
|
||||
public float GrabbedDamper = 3;
|
||||
|
||||
[Tooltip("Angular Damper when the dial is not grabbed")]
|
||||
public float Damper = 3;
|
||||
|
||||
[Tooltip("Optional spring value of the joint to return to starting rotation if desired")]
|
||||
public float Spring;
|
||||
|
||||
[Header("Editor")]
|
||||
[SerializeField]
|
||||
protected Quaternion JointStartRotation;
|
||||
|
||||
[Header("Debugging Tools")]
|
||||
public float TargetAngularVelocity = 0f;
|
||||
|
||||
public Rigidbody Rigidbody { get; private set; }
|
||||
|
||||
public HVRGrabbable Grabbable { get; private set; }
|
||||
|
||||
public ConfigurableJoint Joint { get; set; }
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
Rigidbody = this.GetRigidbody();
|
||||
|
||||
Rigidbody.useGravity = !DisableGravity;
|
||||
|
||||
Grabbable = GetComponent<HVRGrabbable>();
|
||||
if (Grabbable)
|
||||
{
|
||||
Grabbable.HandGrabbed.AddListener(OnDialGrabbed);
|
||||
Grabbable.HandReleased.AddListener(OnDialReleased);
|
||||
}
|
||||
|
||||
FixAngle(ref MinAngle, ref MaxAngle);
|
||||
|
||||
SetupJoint();
|
||||
AfterJointCreated(Joint);
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (TargetAngularVelocity > 0f || TargetAngularVelocity < 0f) Joint.targetAngularVelocity = new Vector3(TargetAngularVelocity, 0f, 0f);
|
||||
}
|
||||
|
||||
protected virtual void OnDialReleased(HVRHandGrabber arg0, HVRGrabbable arg1)
|
||||
{
|
||||
Joint.SetAngularXDrive(Spring, Damper, 10000f);
|
||||
if (StopOnRelease)
|
||||
{
|
||||
Rigidbody.angularVelocity = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDialGrabbed(HVRHandGrabber arg0, HVRGrabbable arg1)
|
||||
{
|
||||
Joint.SetAngularXDrive(0f, GrabbedDamper, 10000f);
|
||||
}
|
||||
|
||||
protected virtual void SetupJoint()
|
||||
{
|
||||
var currentRotation = transform.localRotation;
|
||||
transform.localRotation = JointStartRotation;
|
||||
Joint = gameObject.AddComponent<ConfigurableJoint>();
|
||||
Joint.connectedBody = ConnectedBody;
|
||||
Joint.LockLinearMotion();
|
||||
Joint.LockAngularYMotion();
|
||||
Joint.LockAngularZMotion();
|
||||
Joint.anchor = Vector3.zero;
|
||||
Joint.axis = Axis.GetVector();
|
||||
|
||||
if (LimitRotation)
|
||||
{
|
||||
ResetLimits();
|
||||
}
|
||||
else
|
||||
{
|
||||
Joint.angularXMotion = ConfigurableJointMotion.Free;
|
||||
}
|
||||
|
||||
Joint.secondaryAxis = Joint.axis.OrthogonalVector();
|
||||
Joint.SetAngularXDrive(Spring, Damper, 10000f);
|
||||
Joint.projectionAngle = 1f;
|
||||
Joint.projectionDistance = .01f;
|
||||
Joint.projectionMode = JointProjectionMode.PositionAndRotation;
|
||||
transform.localRotation = currentRotation;
|
||||
}
|
||||
|
||||
protected virtual void AfterJointCreated(ConfigurableJoint joint)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the rotation limits on the Joint's main rotation axis
|
||||
/// </summary>
|
||||
public void SetLimits(float minAngle, float maxAngle)
|
||||
{
|
||||
FixAngle(ref minAngle, ref maxAngle);
|
||||
|
||||
Joint.LimitAngularXMotion();
|
||||
Joint.SetAngularXHighLimit(minAngle);
|
||||
Joint.SetAngularXLowLimit(maxAngle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the limit's to the -MinAngle and MaxAngle values of this component.
|
||||
/// </summary>
|
||||
public void ResetLimits()
|
||||
{
|
||||
Joint.LimitAngularXMotion();
|
||||
Joint.SetAngularXHighLimit(-MinAngle);
|
||||
Joint.SetAngularXLowLimit(-MaxAngle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Frees the axis of rotation
|
||||
/// </summary>
|
||||
public void RemoveLimits()
|
||||
{
|
||||
Joint.angularXMotion = ConfigurableJointMotion.Free;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanity check on the angles for the joint high and low settings
|
||||
/// </summary>
|
||||
private void FixAngle(ref float min, ref float max)
|
||||
{
|
||||
if (min > 0)
|
||||
{
|
||||
min *= -1;
|
||||
}
|
||||
|
||||
if (max < 0)
|
||||
{
|
||||
max *= -1;
|
||||
}
|
||||
|
||||
min = Mathf.Clamp(min, min, 0);
|
||||
max = Mathf.Clamp(max, 0, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2cd0e73266090f94ea7927da1368c184
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,422 @@
|
||||
using System.Collections;
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.ScriptableObjects;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// This component helps setup the basic functionality of a hinged door.
|
||||
/// Includes locking and latching capability. Handle required rotation for unlatching.
|
||||
/// </summary>
|
||||
[HelpURL("https://cloudwalker2020.github.io/HurricaneVR-Docs/manual/components/door.html")]
|
||||
[RequireComponent(typeof(HVRRotationTracker))]
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public class HVRPhysicsDoor : MonoBehaviour
|
||||
{
|
||||
[Header("Settings")] [Tooltip("Local axis of rotation")]
|
||||
public HVRAxis Axis;
|
||||
|
||||
[Tooltip("Door's rigidbody mass.")] public float Mass = 10f;
|
||||
|
||||
public bool DisableGravity = true;
|
||||
|
||||
[Tooltip("If true the door and it's handle will have their joint limit's locked on start.")]
|
||||
public bool StartLocked;
|
||||
|
||||
[Tooltip("Rigidbody to connect the joint to")]
|
||||
public Rigidbody ConnectedBody;
|
||||
|
||||
[Header("Door Closing Settings")] [Tooltip("Angle threshold to determine if the door is closed or not.")]
|
||||
public float CloseAngle = 5f;
|
||||
|
||||
[Tooltip("The door will automatically shut over this amount of time once it's close enough to be closed.")]
|
||||
public float CloseOverTime = .25f;
|
||||
|
||||
[Tooltip("How long the door angle must be below 'CloseAngle' to become closed.")]
|
||||
public float CloseDetectionTime = .5f;
|
||||
|
||||
[Header("SFX")] [Tooltip("Angle threshold to play opening and closing sound effects.")]
|
||||
public float SFXThresholdAngle = 2.5f;
|
||||
|
||||
public float SFXResetThreshold = 1f;
|
||||
public AudioClip SFXOpened;
|
||||
public AudioClip SFXClosed;
|
||||
|
||||
[Tooltip("Delay before the open / close sfx can be played again")]
|
||||
public float SFXTimeout = 1f;
|
||||
|
||||
[Tooltip("Optional transform to define the position of the open / close sound fx.")]
|
||||
public Transform SFXPosition;
|
||||
|
||||
[Header("Handle")] [Tooltip("If true the handle must rotate beyond 'HandThreshold' amount of degrees before it will unlatch, if false the door will not latch automatically.")]
|
||||
public bool HandleRequiresRotation;
|
||||
|
||||
[Tooltip("Required handle rotation to unlatch the door.")]
|
||||
public float HandleThreshold = 45f;
|
||||
|
||||
[Tooltip("The rotation tracker that reports the amount of rotation of the handle.")]
|
||||
public HVRRotationTracker HandleRotationTracker;
|
||||
|
||||
[Tooltip("If provided (and held) the door will not automatically shut when it is below 'CloseAngle' in degrees.")]
|
||||
public HVRGrabbable HandleGrabbable;
|
||||
|
||||
[Tooltip("Rotational physics component that let's this door component lock the door handle's rotation when the door locks.")]
|
||||
public HVRPhysicsDial DoorKnob;
|
||||
|
||||
|
||||
[Tooltip("The rotation tracker that reports the amount of rotation of the handle.")]
|
||||
public HVRRotationTracker SecondHandleRotationTracker;
|
||||
|
||||
[Tooltip("If provided (and held) the door will not automatically shut when it is below 'CloseAngle' in degrees.")]
|
||||
public HVRGrabbable SecondHandleGrabbable;
|
||||
|
||||
[Tooltip("Rotational physics component that let's this door component lock the door handle's rotation when the door locks.")]
|
||||
public HVRPhysicsDial SecondDoorKnob;
|
||||
|
||||
[Header("Joint Limits")] public bool LimitRotation = true;
|
||||
|
||||
[Tooltip("Minimum Angle about the axis of rotation")]
|
||||
public float MinAngle;
|
||||
|
||||
[Tooltip("Maximum rotation about the axis of rotation")]
|
||||
public float MaxAngle;
|
||||
|
||||
[Header("Joint Settings")] [Tooltip("Angular Damper of the door hinge.")]
|
||||
public float Damper = 10;
|
||||
|
||||
[Tooltip("Angular Spring that will return the door to it's starting rotation")]
|
||||
public float Spring;
|
||||
|
||||
//[Header("Editor")]
|
||||
//[SerializeField]
|
||||
//protected Quaternion JointStartRotation;
|
||||
|
||||
[Header("Debugging")] public float TargetAngularVelocity = 0f;
|
||||
public bool DoorLatched;
|
||||
public bool DoorClosed;
|
||||
public bool Opened;
|
||||
public bool Closed;
|
||||
public bool PreviousDoorLatched;
|
||||
public bool PreviousClosed;
|
||||
public bool VerboseLogging;
|
||||
public bool Locked;
|
||||
|
||||
public Rigidbody Rigidbody { get; private set; }
|
||||
|
||||
public HVRRotationTracker Tracker { get; private set; }
|
||||
|
||||
protected ConfigurableJoint Joint { get; set; }
|
||||
|
||||
private Quaternion _startRotation;
|
||||
private bool _doorClosing;
|
||||
private float _detectionTimer;
|
||||
private float _lastClosedSFXTime;
|
||||
private float _lastOpenedSFXTime;
|
||||
|
||||
public virtual void Start()
|
||||
{
|
||||
Rigidbody = this.GetRigidbody();
|
||||
Rigidbody.mass = Mass;
|
||||
Rigidbody.useGravity = !DisableGravity;
|
||||
|
||||
Tracker = GetComponent<HVRRotationTracker>();
|
||||
|
||||
if (MinAngle > 0)
|
||||
{
|
||||
MinAngle *= -1;
|
||||
}
|
||||
|
||||
if (MaxAngle < 0)
|
||||
{
|
||||
MaxAngle *= -1;
|
||||
}
|
||||
|
||||
MinAngle = Mathf.Clamp(MinAngle, MinAngle, 0);
|
||||
MaxAngle = Mathf.Clamp(MaxAngle, 0, MaxAngle);
|
||||
|
||||
if (HandleRequiresRotation)
|
||||
{
|
||||
if (!HandleRotationTracker)
|
||||
{
|
||||
Debug.LogError("HandleRotationTracker not assigned.");
|
||||
}
|
||||
|
||||
DoorLatched = true;
|
||||
}
|
||||
|
||||
DoorClosed = true;
|
||||
PreviousDoorLatched = DoorLatched;
|
||||
PreviousClosed = DoorClosed;
|
||||
|
||||
SetupJoint();
|
||||
|
||||
_startRotation = transform.localRotation;
|
||||
|
||||
if (DoorLatched)
|
||||
{
|
||||
LockDoorJoint();
|
||||
}
|
||||
|
||||
if (StartLocked)
|
||||
{
|
||||
Lock();
|
||||
}
|
||||
|
||||
//set initial values to prevent sfx on start
|
||||
if (Tracker.UnsignedAngle < SFXThresholdAngle)
|
||||
{
|
||||
Closed = true;
|
||||
}
|
||||
else if (Tracker.UnsignedAngle > SFXThresholdAngle)
|
||||
{
|
||||
Opened = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
Joint.targetAngularVelocity = new Vector3(TargetAngularVelocity, 0f, 0f);
|
||||
|
||||
if (_doorClosing)
|
||||
return;
|
||||
|
||||
if (Tracker.UnsignedAngle < CloseAngle)
|
||||
{
|
||||
_detectionTimer += Time.deltaTime;
|
||||
}
|
||||
else if (Tracker.UnsignedAngle >= CloseAngle)
|
||||
{
|
||||
_detectionTimer = 0f;
|
||||
DoorClosed = false;
|
||||
}
|
||||
|
||||
if (HandleGrabbable && HandleGrabbable.IsBeingHeld || SecondHandleGrabbable && SecondHandleGrabbable.IsBeingHeld)
|
||||
{
|
||||
_detectionTimer = 0f;
|
||||
}
|
||||
|
||||
if (_detectionTimer > CloseDetectionTime)
|
||||
{
|
||||
DoorClosed = true;
|
||||
}
|
||||
|
||||
if (!PreviousClosed && DoorClosed)
|
||||
{
|
||||
OnDoorClosed();
|
||||
}
|
||||
else if (PreviousClosed && !DoorClosed)
|
||||
{
|
||||
OnDoorOpened();
|
||||
}
|
||||
|
||||
var reset = SFXResetThreshold;
|
||||
if (SFXResetThreshold > SFXThresholdAngle)
|
||||
{
|
||||
reset = SFXThresholdAngle * .5f;
|
||||
}
|
||||
|
||||
if (!Opened && Tracker.UnsignedAngle > SFXThresholdAngle && Time.time - _lastOpenedSFXTime > SFXTimeout)
|
||||
{
|
||||
_lastOpenedSFXTime = Time.time;
|
||||
Opened = true;
|
||||
PlayOpenedSFX();
|
||||
}
|
||||
else if (!Closed && Tracker.UnsignedAngle < SFXThresholdAngle && Time.time - _lastClosedSFXTime > SFXTimeout)
|
||||
{
|
||||
_lastClosedSFXTime = Time.time;
|
||||
Closed = true;
|
||||
PlayClosedSFX();
|
||||
}
|
||||
else if (Opened && Tracker.UnsignedAngle < SFXThresholdAngle - reset)
|
||||
{
|
||||
Opened = false;
|
||||
}
|
||||
else if (Closed && Tracker.UnsignedAngle > SFXThresholdAngle + reset)
|
||||
{
|
||||
Closed = false;
|
||||
}
|
||||
|
||||
if (HandleRequiresRotation)
|
||||
{
|
||||
if (HandleRotationTracker.UnsignedAngle >= HandleThreshold ||
|
||||
(SecondHandleRotationTracker && SecondHandleRotationTracker.UnsignedAngle >= HandleThreshold))
|
||||
{
|
||||
DoorLatched = false;
|
||||
}
|
||||
else if (HandleRotationTracker.UnsignedAngle < HandleThreshold &&
|
||||
(!SecondHandleRotationTracker || SecondHandleRotationTracker.UnsignedAngle < HandleThreshold) &&
|
||||
Tracker.UnsignedAngle < CloseAngle)
|
||||
{
|
||||
DoorLatched = true;
|
||||
}
|
||||
|
||||
if (!Locked)
|
||||
{
|
||||
if (PreviousDoorLatched && !DoorLatched)
|
||||
{
|
||||
OnDoorUnLatched();
|
||||
}
|
||||
else if (!PreviousDoorLatched && DoorLatched)
|
||||
{
|
||||
OnDoorLatched();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PreviousDoorLatched = DoorLatched;
|
||||
PreviousClosed = DoorClosed;
|
||||
}
|
||||
|
||||
protected virtual Vector3 GetSFXPosition()
|
||||
{
|
||||
var position = transform.position;
|
||||
if (SFXPosition)
|
||||
{
|
||||
position = SFXPosition.position;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
protected virtual void PlayClosedSFX()
|
||||
{
|
||||
if (SFXPlayer.Instance) SFXPlayer.Instance.PlaySFX(SFXClosed, GetSFXPosition());
|
||||
}
|
||||
|
||||
|
||||
protected virtual void PlayOpenedSFX()
|
||||
{
|
||||
if (SFXPlayer.Instance) SFXPlayer.Instance.PlaySFX(SFXOpened, GetSFXPosition());
|
||||
}
|
||||
|
||||
public virtual void OnDoorUnLatched()
|
||||
{
|
||||
if (VerboseLogging)
|
||||
Debug.Log($"OnDoorUnLatched");
|
||||
UnlockDoorJoint();
|
||||
}
|
||||
|
||||
public virtual void OnDoorLatched()
|
||||
{
|
||||
if (VerboseLogging)
|
||||
Debug.Log($"OnDoorLatched");
|
||||
LockDoorJoint();
|
||||
}
|
||||
|
||||
// ReSharper disable Unity.PerformanceAnalysis
|
||||
protected virtual void OnDoorClosed()
|
||||
{
|
||||
if (VerboseLogging)
|
||||
Debug.Log($"OnDoorClosed");
|
||||
|
||||
StartCoroutine(DoorCloseRoutine());
|
||||
}
|
||||
|
||||
// ReSharper disable Unity.PerformanceAnalysis
|
||||
protected virtual void OnDoorOpened()
|
||||
{
|
||||
if (VerboseLogging)
|
||||
Debug.Log($"OnDoorOpened");
|
||||
}
|
||||
|
||||
protected virtual void LockDoorJoint()
|
||||
{
|
||||
if (!LimitRotation)
|
||||
return;
|
||||
|
||||
Joint.SetAngularXHighLimit(0);
|
||||
Joint.SetAngularXLowLimit(0);
|
||||
}
|
||||
|
||||
protected virtual void UnlockDoorJoint()
|
||||
{
|
||||
Joint.SetAngularXHighLimit(-MinAngle);
|
||||
Joint.SetAngularXLowLimit(-MaxAngle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locks the door joint, and the door knob's joint.
|
||||
/// </summary>
|
||||
public virtual void Lock()
|
||||
{
|
||||
Locked = true;
|
||||
LockDoorJoint();
|
||||
LockDoorKnob();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unlocks the door and allows the door handle to rotate.
|
||||
/// </summary>
|
||||
public virtual void Unlock()
|
||||
{
|
||||
Locked = false;
|
||||
|
||||
if (!DoorLatched)
|
||||
{
|
||||
UnlockDoorJoint();
|
||||
}
|
||||
|
||||
UnlockDoorKnob();
|
||||
}
|
||||
|
||||
protected virtual void LockDoorKnob()
|
||||
{
|
||||
if (DoorKnob) DoorKnob.SetLimits(0, 0);
|
||||
if (SecondDoorKnob) SecondDoorKnob.SetLimits(0, 0);
|
||||
}
|
||||
|
||||
protected virtual void UnlockDoorKnob()
|
||||
{
|
||||
if (DoorKnob) DoorKnob.ResetLimits();
|
||||
if (SecondDoorKnob) SecondDoorKnob.ResetLimits();
|
||||
}
|
||||
|
||||
protected IEnumerator DoorCloseRoutine()
|
||||
{
|
||||
_doorClosing = true;
|
||||
var startRotation = transform.localRotation;
|
||||
var elapsed = 0f;
|
||||
while (elapsed < CloseOverTime)
|
||||
{
|
||||
transform.localRotation = Quaternion.Lerp(startRotation, _startRotation, elapsed / CloseOverTime);
|
||||
elapsed += Time.deltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
transform.localRotation = _startRotation;
|
||||
_doorClosing = false;
|
||||
}
|
||||
|
||||
protected virtual void SetupJoint()
|
||||
{
|
||||
var currentRotation = transform.localRotation;
|
||||
//transform.localRotation = JointStartRotation;
|
||||
Joint = gameObject.AddComponent<ConfigurableJoint>();
|
||||
Joint.connectedBody = ConnectedBody;
|
||||
Joint.LockLinearMotion();
|
||||
Joint.LockAngularYMotion();
|
||||
Joint.LockAngularZMotion();
|
||||
Joint.anchor = Vector3.zero;
|
||||
Joint.axis = Axis.GetVector();
|
||||
|
||||
if (LimitRotation)
|
||||
{
|
||||
Joint.LimitAngularXMotion();
|
||||
Joint.SetAngularXHighLimit(-MinAngle);
|
||||
Joint.SetAngularXLowLimit(-MaxAngle);
|
||||
}
|
||||
else
|
||||
{
|
||||
Joint.angularXMotion = ConfigurableJointMotion.Free;
|
||||
}
|
||||
|
||||
Joint.secondaryAxis = Joint.axis.OrthogonalVector();
|
||||
Joint.SetAngularXDrive(Spring, Damper, 10000f);
|
||||
|
||||
transform.localRotation = currentRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4eeb3f37d2fe3e547a9a248b2bbf0139
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using HurricaneVR.Framework.Core.ScriptableObjects;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper component to constrain a drawer along the desired movement axis handling the joint creation and limiting for you.
|
||||
/// Joint is constrained between the start and end position which is defined in the component inspector.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public class HVRPhysicsDrawer : MonoBehaviour
|
||||
{
|
||||
[Header("Settings")]
|
||||
[Tooltip("Axis the drawer will travel on in local space.")]
|
||||
public HVRAxis Axis;
|
||||
|
||||
[Tooltip("Rigidbody to joint to.")]
|
||||
public Rigidbody ConnectedBody;
|
||||
|
||||
[Tooltip("Optional spring that will return to the starting position")]
|
||||
public float Spring = 0;
|
||||
|
||||
[Tooltip("Damper to provide 'friction' to the drawer.")]
|
||||
public float Damper = 10;
|
||||
|
||||
[Header("SFX")]
|
||||
public float SFXResetThreshold = .02f;
|
||||
public AudioClip SFXOpened;
|
||||
public AudioClip SFXClosed;
|
||||
|
||||
[Header("Editor Fields")]
|
||||
[Tooltip("The resting position of the button")]
|
||||
public Vector3 StartPosition;
|
||||
|
||||
[Tooltip("Furthest position the button can travel")]
|
||||
public Vector3 EndPosition;
|
||||
|
||||
public Vector3 OpenPosition;
|
||||
|
||||
|
||||
[Header("Debug")]
|
||||
public bool UpdateSpring;
|
||||
public bool PreviousOpened;
|
||||
public bool Opened;
|
||||
public bool PreviousClosed;
|
||||
public bool Closed;
|
||||
|
||||
public Rigidbody Rigidbody { get; private set; }
|
||||
|
||||
private Vector3 _axis;
|
||||
private ConfigurableJoint _joint;
|
||||
private ConfigurableJoint _limitJoint;
|
||||
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
transform.localPosition = StartPosition;
|
||||
Rigidbody = GetComponent<Rigidbody>();
|
||||
_axis = Axis.GetVector();
|
||||
Rigidbody.useGravity = false;
|
||||
SetupJoint();
|
||||
|
||||
//set initial values to prevent sfx on start
|
||||
GetValues(out var distance, out var openedDistance, out var resetThreshold);
|
||||
|
||||
if (distance > openedDistance)
|
||||
{
|
||||
Opened = true;
|
||||
}
|
||||
else if (distance < openedDistance)
|
||||
{
|
||||
Closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupJoint()
|
||||
{
|
||||
_joint = gameObject.AddComponent<ConfigurableJoint>();
|
||||
_joint.connectedBody = ConnectedBody;
|
||||
_joint.autoConfigureConnectedAnchor = false;
|
||||
_joint.anchor = Vector3.zero;
|
||||
|
||||
var worldStartPosition = StartPosition;
|
||||
if (transform.parent)
|
||||
worldStartPosition = transform.parent.TransformPoint(StartPosition);
|
||||
|
||||
var worldEndPosition = EndPosition;
|
||||
if (transform.parent)
|
||||
worldEndPosition = transform.parent.TransformPoint(EndPosition);
|
||||
|
||||
|
||||
if (ConnectedBody)
|
||||
{
|
||||
_joint.connectedAnchor = ConnectedBody.transform.InverseTransformPoint(worldStartPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
_joint.connectedAnchor = worldStartPosition;
|
||||
}
|
||||
|
||||
_joint.SetXDrive(Spring, Damper, Spring);
|
||||
|
||||
_joint.LimitXMotion();
|
||||
_joint.LockYMotion();
|
||||
_joint.LockZMotion();
|
||||
_joint.LockAllAngularMotion();
|
||||
_joint.axis = _axis;
|
||||
_joint.secondaryAxis = _joint.axis.OrthogonalVector();
|
||||
_joint.SetLinearLimit(Vector3.Distance(StartPosition, EndPosition));
|
||||
|
||||
_limitJoint = gameObject.AddComponent<ConfigurableJoint>();
|
||||
_limitJoint.connectedBody = ConnectedBody;
|
||||
_limitJoint.autoConfigureConnectedAnchor = false;
|
||||
_limitJoint.anchor = Vector3.zero;
|
||||
|
||||
if (ConnectedBody)
|
||||
{
|
||||
_limitJoint.connectedAnchor = ConnectedBody.transform.InverseTransformPoint(worldEndPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
_limitJoint.connectedAnchor = worldEndPosition;
|
||||
}
|
||||
|
||||
_limitJoint.LockYMotion();
|
||||
_limitJoint.LockZMotion();
|
||||
_limitJoint.LockAllAngularMotion();
|
||||
_limitJoint.axis = _axis;
|
||||
_limitJoint.secondaryAxis = _joint.axis.OrthogonalVector();
|
||||
_limitJoint.LimitXMotion();
|
||||
_limitJoint.SetLinearLimit(Vector3.Distance(StartPosition, EndPosition));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
GetValues(out var distance, out var openedDistance, out var resetThreshold);
|
||||
|
||||
var closeReset = openedDistance + resetThreshold;
|
||||
var openReset = openedDistance - resetThreshold;
|
||||
|
||||
if (!Opened && distance > openedDistance)
|
||||
{
|
||||
Opened = true;
|
||||
if(SFXPlayer.Instance) SFXPlayer.Instance.PlaySFX(SFXOpened, transform.position);
|
||||
}
|
||||
else if (!Closed && distance < openedDistance)
|
||||
{
|
||||
Closed = true;
|
||||
if(SFXPlayer.Instance) SFXPlayer.Instance.PlaySFX(SFXClosed, transform.position);
|
||||
}
|
||||
else if (Opened && distance < openReset)
|
||||
{
|
||||
Opened = false;
|
||||
}
|
||||
else if (Closed && distance > closeReset)
|
||||
{
|
||||
Closed = false;
|
||||
}
|
||||
|
||||
PreviousClosed = Closed;
|
||||
PreviousOpened = Opened;
|
||||
}
|
||||
|
||||
private void GetValues(out float distance, out float openDistance, out float resetDelta)
|
||||
{
|
||||
distance = 0f;
|
||||
openDistance = 0f;
|
||||
resetDelta = SFXResetThreshold;
|
||||
switch (Axis)
|
||||
{
|
||||
case HVRAxis.X:
|
||||
case HVRAxis.NegX:
|
||||
distance = transform.localPosition.x - StartPosition.x;
|
||||
openDistance = OpenPosition.x - StartPosition.x;
|
||||
break;
|
||||
case HVRAxis.Y:
|
||||
case HVRAxis.NegY:
|
||||
distance = transform.localPosition.y - StartPosition.y;
|
||||
openDistance = OpenPosition.y - StartPosition.y;
|
||||
break;
|
||||
case HVRAxis.Z:
|
||||
case HVRAxis.NegZ:
|
||||
distance = transform.localPosition.z - StartPosition.z;
|
||||
openDistance = OpenPosition.z - StartPosition.z;
|
||||
break;
|
||||
}
|
||||
|
||||
distance = Mathf.Abs(distance);
|
||||
openDistance = Mathf.Abs(openDistance);
|
||||
|
||||
if (resetDelta > openDistance)
|
||||
{
|
||||
resetDelta = openDistance * .5f;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
var forward = (EndPosition - StartPosition).normalized;
|
||||
var closeReset = transform.parent.TransformPoint(OpenPosition + (forward * SFXResetThreshold));
|
||||
var openReset = transform.parent.TransformPoint(OpenPosition - (forward * SFXResetThreshold));
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawWireSphere(closeReset, .005f);
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawWireSphere(openReset, .005f);
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawWireSphere(transform.parent.TransformPoint(OpenPosition), .005f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 465d464c79597514bb491631782942cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.Grabbers;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Lever behaves similar to the dial in rigidbody joint behaviour at this time...
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public class HVRPhysicsLever : HVRPhysicsDial
|
||||
{
|
||||
public bool DrawGizmos = true;
|
||||
|
||||
|
||||
public void OnDrawGizmosSelected()
|
||||
{
|
||||
//if (DrawGizmos)
|
||||
//{
|
||||
// var minVector = Quaternion.Euler(MinAngle * _axis) * _orthogonal;
|
||||
// var maxVector = Quaternion.Euler(MaxAngle * _axis) * _orthogonal;
|
||||
|
||||
// Gizmos.color = Color.green;
|
||||
// Gizmos.DrawLine(transform.position, transform.position + transform.TransformDirection(minVector) * .3f);
|
||||
// Gizmos.color = Color.yellow;
|
||||
// Gizmos.DrawLine(transform.position, transform.position + transform.TransformDirection(maxVector) * .3f);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93ae46635261c874188443083a8deee5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,96 @@
|
||||
using Assets.HurricaneVR.Framework.Shared.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper component to override various rigidbody properties
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
public class HVRRigidBodyOverrides : MonoBehaviour
|
||||
{
|
||||
|
||||
public bool OverrideCOM;
|
||||
public bool OverrideRotation;
|
||||
public bool OverrideTensor;
|
||||
public bool OverrideAngularSpeed;
|
||||
public bool OverrideMaxDepenetration;
|
||||
|
||||
public Vector3 CenterOfMass;
|
||||
public Vector3 InertiaTensorRotation;
|
||||
public Vector3 InertiaTensor;
|
||||
public float MaxAngularVelocity;
|
||||
public float MaxDepenetration;
|
||||
|
||||
[Header("Debug")]
|
||||
public Vector3 COMGizmoSize = new Vector3(.02f, .02f, .02f);
|
||||
public bool LiveUpdate;
|
||||
public bool ShowCOMGizmo;
|
||||
public Rigidbody Rigidbody;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (!Rigidbody)
|
||||
{
|
||||
Rigidbody = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
this.ExecuteNextUpdate(ApplyOverrides);
|
||||
}
|
||||
|
||||
protected virtual void OnValidate()
|
||||
{
|
||||
if (!Rigidbody) TryGetComponent(out Rigidbody);
|
||||
}
|
||||
|
||||
public void ApplyOverrides()
|
||||
{
|
||||
if (OverrideCOM)
|
||||
{
|
||||
Rigidbody.centerOfMass = CenterOfMass;
|
||||
}
|
||||
|
||||
if (OverrideTensor)
|
||||
{
|
||||
Rigidbody.inertiaTensor = InertiaTensor;
|
||||
}
|
||||
|
||||
if (OverrideRotation)
|
||||
{
|
||||
Rigidbody.inertiaTensorRotation = Quaternion.Euler(InertiaTensorRotation);
|
||||
}
|
||||
|
||||
if (OverrideAngularSpeed)
|
||||
{
|
||||
Rigidbody.maxAngularVelocity = MaxAngularVelocity;
|
||||
}
|
||||
|
||||
if (OverrideMaxDepenetration) Rigidbody.maxDepenetrationVelocity = MaxDepenetration;
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
if (LiveUpdate)
|
||||
{
|
||||
ApplyOverrides();
|
||||
}
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
if (ShowCOMGizmo)
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
if (OverrideCOM)
|
||||
{
|
||||
Gizmos.DrawCube(transform.TransformPoint(CenterOfMass), COMGizmoSize);
|
||||
}
|
||||
else if(Rigidbody)
|
||||
{
|
||||
Gizmos.DrawCube(Rigidbody.worldCenterOfMass, COMGizmoSize);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1a0e712065e5ec4484d6ca15e0f4563
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Helps constrain loose joints on the desired axis.
|
||||
/// </summary>
|
||||
public class HVRRigidbodyLocker : MonoBehaviour
|
||||
{
|
||||
public LockOptions Locks;
|
||||
|
||||
private Vector3 _position;
|
||||
private Vector3 _rotation;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_position = transform.localPosition;
|
||||
_rotation = transform.localEulerAngles;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Lock();
|
||||
}
|
||||
|
||||
private void Lock()
|
||||
{
|
||||
var position = transform.localPosition;
|
||||
var rotation = transform.localEulerAngles;
|
||||
|
||||
if ((Locks & LockOptions.PosX) == LockOptions.PosX)
|
||||
{
|
||||
position.x = _position.x;
|
||||
}
|
||||
|
||||
if ((Locks & LockOptions.PosY) == LockOptions.PosY)
|
||||
{
|
||||
position.y = _position.y;
|
||||
}
|
||||
|
||||
if ((Locks & LockOptions.PosZ) == LockOptions.PosZ)
|
||||
{
|
||||
position.z = _position.z;
|
||||
}
|
||||
|
||||
if ((Locks & LockOptions.RotX) == LockOptions.RotX)
|
||||
{
|
||||
rotation.x = _rotation.x;
|
||||
}
|
||||
|
||||
if ((Locks & LockOptions.RotY) == LockOptions.RotY)
|
||||
{
|
||||
rotation.y = _rotation.y;
|
||||
}
|
||||
|
||||
if ((Locks & LockOptions.RotZ) == LockOptions.RotZ)
|
||||
{
|
||||
rotation.z = _rotation.z;
|
||||
}
|
||||
|
||||
transform.localPosition = position;
|
||||
transform.localEulerAngles = rotation;
|
||||
}
|
||||
|
||||
public void LateUpdate()
|
||||
{
|
||||
Lock();
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum LockOptions
|
||||
{
|
||||
None = 0,
|
||||
PosX = 1,
|
||||
PosY = 2,
|
||||
PosZ = 4,
|
||||
RotX = 8,
|
||||
RotY = 16,
|
||||
RotZ = 32
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f268fd1aeab764742be311a0d06b49d3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using HurricaneVR.Framework.Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
[RequireComponent(typeof(MeshRenderer))]
|
||||
public class HVRRingHighlight : HVRScaleHighlight
|
||||
{
|
||||
public Transform Camera;
|
||||
|
||||
[Header("Settings")]
|
||||
|
||||
[Tooltip("Ring must be within this distance from the camera to be displayed")]
|
||||
public float Distance = 5f;
|
||||
|
||||
|
||||
[Header("Line of Sight Settings")]
|
||||
|
||||
[Tooltip("Use ray cast to the camera collider to determine if we should show")]
|
||||
public bool RequireLineOfSight = true;
|
||||
|
||||
[Tooltip("Layer mask for checking line of sight, include the layer of the camera(default is Player)")]
|
||||
public LayerMask LayerMask;
|
||||
|
||||
[Tooltip("Check line of sight only if distance greater than this")]
|
||||
public float LineOfSightThreshold = 1.5f;
|
||||
|
||||
[Tooltip("Timeout to check line of sight")]
|
||||
public float Delay = 1f;
|
||||
|
||||
public MeshRenderer Ring { get; private set; }
|
||||
|
||||
private bool _hasCamera;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
if (!Camera && HVRManager.Instance)
|
||||
{
|
||||
Camera = HVRManager.Instance.Camera;
|
||||
}
|
||||
|
||||
_hasCamera = Camera;
|
||||
|
||||
Ring = GetComponent<MeshRenderer>();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (!_hasCamera)
|
||||
return;
|
||||
|
||||
transform.LookAt(Camera);
|
||||
|
||||
if (!RequireLineOfSight)
|
||||
{
|
||||
var distance = Vector3.Distance(transform.position, Camera.position);
|
||||
if (distance > Distance)
|
||||
{
|
||||
Ring.enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ring.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!RequireLineOfSight || !_hasCamera)
|
||||
return;
|
||||
|
||||
var distance = Vector3.Distance(transform.position, Camera.position);
|
||||
if (distance > Distance)
|
||||
{
|
||||
Ring.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (distance < LineOfSightThreshold)
|
||||
{
|
||||
Ring.enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Physics.Raycast(transform.position, (Camera.position - transform.position).normalized, out var hit, Distance, LayerMask, QueryTriggerInteraction.Ignore))
|
||||
{
|
||||
Ring.enabled = hit.collider.gameObject == Camera.transform.gameObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ring.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
base.Enable();
|
||||
Ring.enabled = true;
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
base.Disable();
|
||||
Ring.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f12566bd4f6404580f543211008456c
|
||||
timeCreated: 1600292559
|
||||
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using HurricaneVR.Framework.Core.ScriptableObjects;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to limit rotations beyond the default Physx limit of 177 degrees. Joint is recreated at certain thresholds to allow the wider
|
||||
/// range of motion, only use this if you need range of motion beyond 177 degrees.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
[RequireComponent(typeof(HVRRotationTracker))]
|
||||
public class HVRRotationLimiter : MonoBehaviour
|
||||
{
|
||||
public const float PhysxMaxLimit = 177f;
|
||||
|
||||
[Tooltip("Connected Body of the Joint")]
|
||||
public Rigidbody ConnectedBody;
|
||||
|
||||
[Tooltip("Minimum angle of rotation")]
|
||||
public int MinAngle;
|
||||
|
||||
[Tooltip("Maximum angle of rotation")]
|
||||
public int MaxAngle;
|
||||
|
||||
[Tooltip("Distance traveled before the joint is recreated with new limits")]
|
||||
public float JointResetThreshold = 90f;
|
||||
|
||||
|
||||
public Rigidbody Rigidbody { get; private set; }
|
||||
|
||||
public HVRRotationTracker Tracker { get; private set; }
|
||||
|
||||
private ConfigurableJoint _joint;
|
||||
private float _angleAtCreation;
|
||||
|
||||
[Header("Debugging")]
|
||||
public float maxDelta;
|
||||
public float minDelta;
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
Rigidbody = this.GetRigidbody();
|
||||
Tracker = GetComponent<HVRRotationTracker>();
|
||||
|
||||
if (MinAngle > 0)
|
||||
{
|
||||
MinAngle *= -1;
|
||||
}
|
||||
|
||||
if (MaxAngle < 0)
|
||||
{
|
||||
MaxAngle *= -1;
|
||||
}
|
||||
|
||||
MinAngle = Mathf.Clamp(MinAngle, MinAngle, 0);
|
||||
MaxAngle = Mathf.Clamp(MaxAngle, 0, MaxAngle);
|
||||
}
|
||||
|
||||
protected virtual void FixedUpdate()
|
||||
{
|
||||
var angle = Mathf.Clamp(Tracker.Angle, MinAngle, MaxAngle);
|
||||
minDelta = Math.Abs(MinAngle - angle);
|
||||
maxDelta = MaxAngle - angle;
|
||||
|
||||
var force = false;
|
||||
if (_joint)
|
||||
{
|
||||
var angleFromJointCreation = angle - _angleAtCreation;
|
||||
var angleDelta = Mathf.Abs(angleFromJointCreation);
|
||||
|
||||
if (angleDelta > JointResetThreshold)
|
||||
{
|
||||
Destroy(_joint);
|
||||
force = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_joint || force)
|
||||
{
|
||||
if (minDelta < PhysxMaxLimit || maxDelta < PhysxMaxLimit)
|
||||
{
|
||||
_joint = gameObject.AddComponent<ConfigurableJoint>();
|
||||
_joint.axis = Tracker.AxisOfRotation;
|
||||
_joint.secondaryAxis = Tracker.AxisOfRotation.OrthogonalVector();
|
||||
_joint.LimitAngularXMotion();
|
||||
_joint.connectedBody = ConnectedBody;
|
||||
|
||||
_angleAtCreation = Tracker.Angle;
|
||||
|
||||
if (minDelta < PhysxMaxLimit)
|
||||
{
|
||||
_joint.SetAngularXHighLimit(minDelta);
|
||||
}
|
||||
else
|
||||
{
|
||||
_joint.SetAngularXHighLimit(PhysxMaxLimit);
|
||||
}
|
||||
|
||||
if (maxDelta < PhysxMaxLimit)
|
||||
{
|
||||
_joint.SetAngularXLowLimit(-maxDelta);
|
||||
}
|
||||
else
|
||||
{
|
||||
_joint.SetAngularXLowLimit(-PhysxMaxLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02aeadf9b7915034d999c6e3161257f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,56 @@
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Used in conjunction with the HVRRotationTracker to play SFX based on rotation amount.
|
||||
/// </summary>
|
||||
public class HVRRotationSFX : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Tracker required to know how far something has rotated")]
|
||||
public HVRRotationTracker Tracker;
|
||||
|
||||
[Tooltip("Clip chosen at random from this list when rotated beyond 'AngleThreshold'")]
|
||||
public AudioClip[] SFX;
|
||||
|
||||
[Tooltip("Rotation distance must exceed this to play another sfx clip")]
|
||||
public float AngleThreshold = 30f;
|
||||
|
||||
[Header("Debug")]
|
||||
public float AngleAccumulated;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
if (Tracker)
|
||||
{
|
||||
Tracker = GetComponent<HVRRotationTracker>();
|
||||
}
|
||||
|
||||
if (Tracker)
|
||||
{
|
||||
Tracker.AngleChanged.AddListener(OnAngleChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAngleChanged(float angle, float delta)
|
||||
{
|
||||
if (SFX != null && SFX.Length > 0)
|
||||
{
|
||||
AngleAccumulated += Mathf.Abs(delta);
|
||||
if (AngleAccumulated > AngleThreshold)
|
||||
{
|
||||
var index = Random.Range(0, SFX.Length);
|
||||
var sfx = SFX[index];
|
||||
AngleAccumulated = 0;
|
||||
PlaySFX(sfx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void PlaySFX(AudioClip sfx)
|
||||
{
|
||||
if(SFXPlayer.Instance) SFXPlayer.Instance.PlaySFX(sfx, transform.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50bacb0498a77b04b867c1791becba25
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to track the rotation in degrees about a defined axis of rotation.
|
||||
/// Degrees are reported from the starting rotation of the transform.
|
||||
/// </summary>
|
||||
public class HVRRotationTracker : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Local axis of rotation")]
|
||||
public HVRAxis Axis;
|
||||
|
||||
[Tooltip("Number of Steps")]
|
||||
public int Steps;
|
||||
|
||||
[Tooltip("Threshold to reach to fire the Angle changed method and events")]
|
||||
public float AngleThreshold = 1f;
|
||||
|
||||
[Tooltip("Max angle for Step Size calculation, should match limits set on whatever is controlling the rotational limits of this object")]
|
||||
public float MaximumAngle = 360f;
|
||||
|
||||
public RotationTrackerStepEvent StepChanged = new RotationTrackerStepEvent();
|
||||
public RotationTrackerAngleEvent AngleChanged = new RotationTrackerAngleEvent();
|
||||
|
||||
[Header("Debug")]
|
||||
|
||||
public float StepSize;
|
||||
public int Step;
|
||||
|
||||
private Vector3 _angleVector;
|
||||
private float _previousAngle;
|
||||
private Vector3 _trackAxis;
|
||||
private Vector3 _startVector;
|
||||
|
||||
[SerializeField]
|
||||
private float _clampedAngle;
|
||||
[SerializeField]
|
||||
private float _angleFromStart;
|
||||
|
||||
public float ClampedAngle { get; private set; }
|
||||
public float Angle { get; private set; }
|
||||
|
||||
public float UnsignedAngle => Mathf.Abs(Angle);
|
||||
|
||||
public Vector3 AxisOfRotation { get; private set; }
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
AxisOfRotation = Axis.GetVector();
|
||||
AxisOfRotation.Normalize();
|
||||
_trackAxis = AxisOfRotation.OrthogonalVector();
|
||||
|
||||
_startVector = transform.localRotation * _trackAxis;
|
||||
|
||||
if (Steps <= 1)
|
||||
{
|
||||
StepSize = 0f;
|
||||
}
|
||||
else if (Steps > 1 && Mathf.Approximately(StepSize, 0f))
|
||||
{
|
||||
StepSize = MaximumAngle / Steps;
|
||||
}
|
||||
|
||||
_angleVector = _startVector;
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
var currentVector = transform.localRotation * _trackAxis;
|
||||
|
||||
ClampedAngle = Vector3.SignedAngle(_startVector, currentVector, AxisOfRotation);
|
||||
|
||||
if (ClampedAngle < 0)
|
||||
{
|
||||
ClampedAngle += 360;
|
||||
}
|
||||
|
||||
var angleDelta = Vector3.SignedAngle(_angleVector, currentVector, AxisOfRotation);
|
||||
if (Mathf.Abs(angleDelta) > AngleThreshold)
|
||||
{
|
||||
_angleVector = currentVector;
|
||||
Angle += angleDelta;
|
||||
OnAngleChanged(ClampedAngle, angleDelta);
|
||||
}
|
||||
|
||||
var stepAngle = ClampedAngle;
|
||||
if (Steps > 1)
|
||||
{
|
||||
Step = Mathf.RoundToInt(ClampedAngle / StepSize);
|
||||
stepAngle = Step * StepSize;
|
||||
if (Mathf.Approximately(stepAngle, 360))
|
||||
{
|
||||
Step = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Steps > 1)
|
||||
{
|
||||
if (!Mathf.Approximately(stepAngle, _previousAngle))
|
||||
{
|
||||
OnStepChanged(Step, true);
|
||||
_previousAngle = stepAngle;
|
||||
}
|
||||
}
|
||||
|
||||
_angleFromStart = Angle;
|
||||
_clampedAngle = ClampedAngle;
|
||||
}
|
||||
|
||||
protected virtual void OnStepChanged(int step, bool raiseEvents)
|
||||
{
|
||||
StepChanged.Invoke(step);
|
||||
}
|
||||
|
||||
protected virtual void OnAngleChanged(float angle, float delta)
|
||||
{
|
||||
AngleChanged.Invoke(angle, delta);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RotationTrackerAngleEvent : UnityEvent<float, float> { }
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class RotationTrackerStepEvent : UnityEvent<int> { }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80e9f8f507f775b4aa48c08844126549
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Specialized hover behaviour that scales this transform over time when a hand or force grabber is hovering it.
|
||||
/// </summary>
|
||||
public class HVRScaleHighlight : HVRGrabbableHoverBase
|
||||
{
|
||||
public Vector3 HoverScale = new Vector3(1.3f, 1.3f, 1.3f);
|
||||
public Vector3 UnhoverScale = new Vector3(.1f, .1f, .1f);
|
||||
public float ScaleSpeed = .05f;
|
||||
|
||||
private Vector3 _targetScale;
|
||||
private Vector3 _originalScale;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_originalScale = transform.localScale;
|
||||
_targetScale = _originalScale;
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
transform.localScale = Vector3.Lerp(transform.localScale, _targetScale, ScaleSpeed);
|
||||
}
|
||||
|
||||
public override void Hover()
|
||||
{
|
||||
_targetScale = HoverScale;
|
||||
}
|
||||
|
||||
public override void Unhover()
|
||||
{
|
||||
_targetScale = UnhoverScale;
|
||||
}
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
_targetScale = UnhoverScale;
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
_targetScale = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74b910c8c3f34ee5bb44c0358f637ecc
|
||||
timeCreated: 1600274255
|
||||
@@ -0,0 +1,67 @@
|
||||
using HurricaneVR.Framework.ControllerInput;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to define center of mass of the controller relative to the hand for bonus throwing velocity calculations
|
||||
/// </summary>
|
||||
public class HVRThrowingCenterOfMass : MonoBehaviour
|
||||
{
|
||||
public HVRHandSide HandSide;
|
||||
public Transform Oculus;
|
||||
public Transform Vive;
|
||||
public Transform WMR;
|
||||
public Transform Knuckles;
|
||||
public Transform Fallback;
|
||||
|
||||
public Transform CenterOfMass;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (HandSide == HVRHandSide.Left)
|
||||
{
|
||||
if (HVRInputManager.Instance.LeftController)
|
||||
ControllerConnected(HVRInputManager.Instance.LeftController);
|
||||
HVRInputManager.Instance.LeftControllerConnected.AddListener(ControllerConnected);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HVRInputManager.Instance.RightController)
|
||||
ControllerConnected(HVRInputManager.Instance.RightController);
|
||||
HVRInputManager.Instance.RightControllerConnected.AddListener(ControllerConnected);
|
||||
}
|
||||
}
|
||||
|
||||
private void ControllerConnected(HVRController controller)
|
||||
{
|
||||
|
||||
switch (controller.ControllerType)
|
||||
{
|
||||
case HVRControllerType.Pico:
|
||||
case HVRControllerType.Oculus:
|
||||
CenterOfMass = Oculus;
|
||||
break;
|
||||
case HVRControllerType.ReverbG2:
|
||||
case HVRControllerType.WMR:
|
||||
CenterOfMass = WMR;
|
||||
break;
|
||||
case HVRControllerType.Vive:
|
||||
CenterOfMass = Vive;
|
||||
break;
|
||||
case HVRControllerType.Knuckles:
|
||||
CenterOfMass = Knuckles;
|
||||
break;
|
||||
default:
|
||||
CenterOfMass = Fallback;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!CenterOfMass)
|
||||
CenterOfMass = Fallback;
|
||||
if (!CenterOfMass)
|
||||
CenterOfMass = transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f52676b29554048a64664a7a53a126e
|
||||
timeCreated: 1601260700
|
||||
@@ -0,0 +1,77 @@
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.Grabbers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Framework.Components
|
||||
{
|
||||
//Useful if this grabbable is a single handed grabbable attached to another.
|
||||
//If the other grabbable is grabbed this one will have it's two handed settings forced to be used
|
||||
|
||||
[RequireComponent(typeof(HVRGrabbable))]
|
||||
public class HVRTwoHandStrength : MonoBehaviour
|
||||
{
|
||||
public HVRGrabbable[] Others;
|
||||
|
||||
public HVRGrabbable Grabbable { get; private set; }
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
Grabbable = GetComponent<HVRGrabbable>();
|
||||
|
||||
Grabbable.HandGrabbed.AddListener(OnHandGrabbed);
|
||||
Grabbable.HandReleased.AddListener(OnHandReleased);
|
||||
|
||||
if (Others != null)
|
||||
{
|
||||
foreach (var other in Others)
|
||||
{
|
||||
if (other)
|
||||
{
|
||||
other.HandGrabbed.AddListener(OnOtherGrabbableHandGrabbed);
|
||||
other.HandReleased.AddListener(OnOtherGrabbableHandReleased);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHandReleased(HVRHandGrabber arg0, HVRGrabbable arg1)
|
||||
{
|
||||
Grabbable.ForceTwoHandSettings = false;
|
||||
}
|
||||
|
||||
private void OnHandGrabbed(HVRHandGrabber arg0, HVRGrabbable arg1)
|
||||
{
|
||||
foreach (var other in Others)
|
||||
{
|
||||
if (other.HandGrabbers.Count > 0)
|
||||
{
|
||||
Grabbable.ForceTwoHandSettings = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOtherGrabbableHandReleased(HVRHandGrabber arg0, HVRGrabbable g)
|
||||
{
|
||||
//handle scenario if two "others" are held, then one was released.
|
||||
var force = false;
|
||||
for (int i = 0; i < Others.Length; i++)
|
||||
{
|
||||
var other = Others[i];
|
||||
if (other == g || other.HandGrabbers.Count == 0)
|
||||
continue;
|
||||
|
||||
force = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!force)
|
||||
Grabbable.ForceTwoHandSettings = false;
|
||||
}
|
||||
|
||||
private void OnOtherGrabbableHandGrabbed(HVRHandGrabber arg0, HVRGrabbable arg1)
|
||||
{
|
||||
Grabbable.ForceTwoHandSettings = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a09a78d26498d0459d4d698c39e3a28
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user