Replace UltimateXR with HurricaneVR
This commit is contained in:
@@ -0,0 +1,467 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using HurricaneVR.Framework.Core;
|
||||
using HurricaneVR.Framework.Core.Grabbers;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace HurricaneVR.Framework.Weapons.Guns
|
||||
{
|
||||
public class HVRCockingHandle : HVRGunPart
|
||||
{
|
||||
|
||||
[Header("Settings")]
|
||||
|
||||
[Tooltip("Forward speed of the slide when released")]
|
||||
public float ForwardSpeed = 10f;
|
||||
|
||||
[Tooltip("Faux difficulty for pulling back the handle")]
|
||||
public float Difficulty = .05f;
|
||||
|
||||
[Tooltip("If the handle was popped open due to out of ammo, it will release immediately upon being grabbed")]
|
||||
public bool ImmediateReleaseWhenOpen = true;
|
||||
|
||||
[Tooltip("If true, locks back even if the handle isn't reciprocating")]
|
||||
public bool LockBackOverride;
|
||||
|
||||
public HVRCockingHandleType Type;
|
||||
|
||||
[Header("Lock Options")]
|
||||
public bool LocksForward;
|
||||
|
||||
public bool TriggerUnlocks;
|
||||
public float TriggerThreshold = .7f;
|
||||
|
||||
[Tooltip("Hand must move this fast to unlock the handle")]
|
||||
public float AccelerationThreshold = 2f;
|
||||
|
||||
[Header("Components")]
|
||||
|
||||
public HVRGrabbable Grabbable;
|
||||
|
||||
[Tooltip("Bolt that moves with the charging handle, pump")]
|
||||
public HVRGunBolt Bolt;
|
||||
|
||||
|
||||
[Header("Editor Positions")]
|
||||
|
||||
[Tooltip("Position to reach to eject the chambered round")]
|
||||
public Vector3 EjectPosition;
|
||||
|
||||
[Tooltip("Position to reach that will chamber a round.")]
|
||||
public Vector3 ChamberRoundPosition;
|
||||
|
||||
public List<HVRGunPart> AnimatedParts = new List<HVRGunPart>();
|
||||
|
||||
[Header("Slide Events")]
|
||||
public UnityEvent Released = new UnityEvent();
|
||||
public UnityEvent EjectReached = new UnityEvent();
|
||||
public UnityEvent ChamberRound = new UnityEvent();
|
||||
|
||||
|
||||
private Transform _grabbedPositionTracker;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The offset of the cocking handle when it's grabbed
|
||||
/// </summary>
|
||||
protected float GrabOffset { get; set; }
|
||||
|
||||
public bool EmptyOpen { get; protected set; }
|
||||
|
||||
public Vector3 ForwardPositionWorld => transform.parent.TransformPoint(ForwardPosition);
|
||||
public Vector3 MaxPositionWorld => transform.parent.TransformPoint(BackwardPosition);
|
||||
|
||||
public Vector3 BackDirectionWorld => (MaxPositionWorld - ForwardPositionWorld).normalized;
|
||||
|
||||
private float _chamberedRequiredDistance;
|
||||
private bool _chamberDistanceReached;
|
||||
|
||||
private float _maximumDistance;
|
||||
|
||||
private float _ejectDistance;
|
||||
private bool _ejectDistanceReached;
|
||||
|
||||
private float _lockDistance;
|
||||
private bool _lockDistanceReached;
|
||||
|
||||
private Vector3 _previousHandPosition;
|
||||
private Vector3 _previousVelocity;
|
||||
private Vector3 _handAcceleration;
|
||||
|
||||
private bool _locked = true;
|
||||
|
||||
private Coroutine _forwardRoutine;
|
||||
|
||||
public virtual bool LocksBack
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Type == HVRCockingHandleType.Reciprocating)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return LockBackOverride;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
if (!Grabbable)
|
||||
{
|
||||
Grabbable = GetComponent<HVRGrabbable>();
|
||||
}
|
||||
|
||||
if (Grabbable)
|
||||
{
|
||||
Grabbable.HandGrabbed.AddListener(OnGrabbed);
|
||||
Grabbable.HandReleased.AddListener(OnReleased);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"{name} is missing it's grabbable component.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
var go = new GameObject("GrabTracker");
|
||||
go.transform.parent = transform.parent;
|
||||
_grabbedPositionTracker = go.transform;
|
||||
|
||||
_chamberedRequiredDistance = Vector3.Distance(ChamberRoundPosition, ForwardPosition);
|
||||
_maximumDistance = Vector3.Distance(BackwardPosition, ForwardPosition);
|
||||
_ejectDistance = Vector3.Distance(EjectPosition, ForwardPosition);
|
||||
_lockDistance = _maximumDistance * .05f;
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
Grabbable.CanBeGrabbed = true;
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
Grabbable.CanBeGrabbed = false;
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (Grabbable.HandGrabbers.Count > 0)
|
||||
{
|
||||
UpdateHandTracking();
|
||||
|
||||
if (_locked)
|
||||
{
|
||||
if (CheckUnlock())
|
||||
{
|
||||
Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
if (_locked && LocksForward)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var pullDirection = (Grabbable.HandGrabbers[0].TrackedController.position - _grabbedPositionTracker.position);
|
||||
var backDirection = (MaxPositionWorld - ForwardPositionWorld).normalized * 10;
|
||||
var amount = Vector3.Dot(pullDirection, backDirection) * Difficulty;
|
||||
|
||||
if (amount + GrabOffset > 0)
|
||||
{
|
||||
UpdatePosition(amount);
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.localPosition = ForwardPosition;
|
||||
}
|
||||
|
||||
var distance = Vector3.Distance(transform.position, ForwardPositionWorld);
|
||||
|
||||
CheckEject(distance);
|
||||
CheckChamberDistance(distance);
|
||||
ClampPullBack(distance, BackDirectionWorld);
|
||||
MoveBolt();
|
||||
AnimateParts();
|
||||
CheckLock(distance);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CheckLock(float distance)
|
||||
{
|
||||
if (!LocksForward)
|
||||
return;
|
||||
|
||||
if (distance > _lockDistance && !_lockDistanceReached)
|
||||
{
|
||||
_lockDistanceReached = true;
|
||||
}
|
||||
else if (distance < _lockDistance && _lockDistanceReached)
|
||||
{
|
||||
Close();
|
||||
_lockDistanceReached = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePosition(float amount)
|
||||
{
|
||||
transform.position = ForwardPositionWorld + BackDirectionWorld * (amount + GrabOffset);
|
||||
}
|
||||
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
_locked = true;
|
||||
//Debug.Log($"lock");
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
_locked = false;
|
||||
//Debug.Log($"unlock");
|
||||
}
|
||||
|
||||
protected virtual bool CheckUnlock()
|
||||
{
|
||||
if (!LocksForward)
|
||||
return true;
|
||||
|
||||
if (TriggerUnlocks)
|
||||
{
|
||||
if (Grabbable.HandGrabbers.Count > 0)
|
||||
{
|
||||
if (Grabbable.HandGrabbers[0].Controller.Trigger > TriggerThreshold)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_handAcceleration.magnitude > AccelerationThreshold)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void CheckEject(float distance)
|
||||
{
|
||||
if (distance > _ejectDistance && !_ejectDistanceReached)
|
||||
{
|
||||
EjectReached.Invoke();
|
||||
_ejectDistanceReached = true;
|
||||
}
|
||||
else if (distance < _ejectDistance && _ejectDistanceReached)
|
||||
{
|
||||
_ejectDistanceReached = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CheckChamberDistance(float distance)
|
||||
{
|
||||
if (distance > _chamberedRequiredDistance)
|
||||
{
|
||||
if (!_chamberDistanceReached)
|
||||
{
|
||||
_chamberDistanceReached = true;
|
||||
}
|
||||
}
|
||||
else if (distance < _chamberedRequiredDistance && _chamberDistanceReached)
|
||||
{
|
||||
_chamberDistanceReached = false;
|
||||
ChamberRound.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ClampPullBack(float distance, Vector3 backDirection)
|
||||
{
|
||||
if (distance > _maximumDistance)
|
||||
{
|
||||
transform.localPosition = BackwardPosition;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateHandTracking()
|
||||
{
|
||||
if (!Grabbable.IsBeingHeld)
|
||||
return;
|
||||
|
||||
if (Grabbable.PrimaryGrabber.IsHandGrabber)
|
||||
{
|
||||
var hand = Grabbable.HandGrabbers[0];
|
||||
var velocity = hand.TrackedController.position - _previousHandPosition;
|
||||
_handAcceleration = (velocity - _previousVelocity) / Time.deltaTime;
|
||||
_previousVelocity = velocity;
|
||||
_previousHandPosition = hand.TrackedController.position;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void MoveBolt()
|
||||
{
|
||||
if (Bolt)
|
||||
{
|
||||
if (_ejectDistance == 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var percent = Vector3.Distance(transform.localPosition, ForwardPosition) / _maximumDistance;
|
||||
|
||||
if (percent > .90)
|
||||
{
|
||||
Bolt.IsPushedBack = false;
|
||||
}
|
||||
|
||||
if (Bolt.IsPushedBack && percent < .90)
|
||||
return;
|
||||
Bolt.Move(percent);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void AnimateParts()
|
||||
{
|
||||
var percent = Vector3.Distance(transform.localPosition, ForwardPosition) / _maximumDistance;
|
||||
|
||||
foreach (var part in AnimatedParts)
|
||||
{
|
||||
part.Animate(percent, CycleDirection.Backward);
|
||||
}
|
||||
}
|
||||
|
||||
public void Move(float percent)
|
||||
{
|
||||
transform.localPosition = Vector3.Lerp(ForwardPosition, BackwardPosition, percent);
|
||||
}
|
||||
|
||||
protected virtual void OnGrabbed(HVRHandGrabber grabber, HVRGrabbable slide)
|
||||
{
|
||||
GrabOffset = 0f;
|
||||
|
||||
if (ImmediateReleaseWhenOpen && EmptyOpen && LocksBack)
|
||||
{
|
||||
if (Bolt)
|
||||
{
|
||||
Bolt.IsPushedBack = false;
|
||||
}
|
||||
Grabbable.ForceRelease();
|
||||
}
|
||||
|
||||
_previousHandPosition = grabber.TrackedController.position;
|
||||
_previousVelocity = Vector3.zero;
|
||||
if (Type == HVRCockingHandleType.Pump)
|
||||
{
|
||||
_grabbedPositionTracker.position = grabber.GrabPoint.position;
|
||||
}
|
||||
else
|
||||
{
|
||||
_grabbedPositionTracker.localPosition = transform.parent.InverseTransformPoint(_previousHandPosition);
|
||||
GrabOffset = Vector3.Distance(ForwardPositionWorld, transform.position);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void OnReleased(HVRHandGrabber grabber, HVRGrabbable slide)
|
||||
{
|
||||
EmptyOpen = false;
|
||||
if (Type != HVRCockingHandleType.Pump)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (_forwardRoutine != null)
|
||||
return;
|
||||
StartCoroutine(ForwardRoutine());
|
||||
}
|
||||
|
||||
protected virtual IEnumerator ForwardRoutine()
|
||||
{
|
||||
Grabbable.CanBeGrabbed = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var distance = Vector3.Distance(transform.localPosition, ForwardPosition);
|
||||
var travel = ForwardSpeed * Time.deltaTime;
|
||||
|
||||
if (distance < travel)
|
||||
{
|
||||
transform.localPosition = ForwardPosition;
|
||||
MoveBolt();
|
||||
AnimateParts();
|
||||
break;
|
||||
}
|
||||
|
||||
transform.localPosition = Vector3.MoveTowards(transform.localPosition, ForwardPosition, travel);
|
||||
AnimateParts();
|
||||
MoveBolt();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
_forwardRoutine = null;
|
||||
Grabbable.CanBeGrabbed = true;
|
||||
|
||||
if (_chamberDistanceReached)
|
||||
{
|
||||
ChamberRound.Invoke();
|
||||
}
|
||||
|
||||
Released.Invoke();
|
||||
_chamberDistanceReached = false;
|
||||
_ejectDistanceReached = false;
|
||||
EmptyOpen = false;
|
||||
|
||||
if (LocksForward)
|
||||
{
|
||||
Lock();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void PushBack()
|
||||
{
|
||||
if (LocksBack)
|
||||
{
|
||||
transform.localPosition = EjectPosition;
|
||||
EmptyOpen = true;
|
||||
_chamberDistanceReached = true;
|
||||
if (Bolt)
|
||||
{
|
||||
Bolt.Move(1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Animate(float percent, CycleDirection direction)
|
||||
{
|
||||
if (Type == HVRCockingHandleType.Reciprocating)
|
||||
{
|
||||
Move(percent);
|
||||
}
|
||||
}
|
||||
|
||||
//public void OnDrawGizmosSelected()
|
||||
//{
|
||||
// Gizmos.color = Color.green;
|
||||
// Gizmos.DrawCube(ForwardPositionWorld, new Vector3(.025f, .025f, .025f));
|
||||
// Gizmos.color = Color.red;
|
||||
// Gizmos.DrawCube(MaxPositionWorld, new Vector3(.025f, .025f, .025f));
|
||||
// Gizmos.color = Color.yellow;
|
||||
// Gizmos.DrawCube(transform.parent.TransformPoint(EjectPosition), new Vector3(.025f, .025f, .025f));
|
||||
// Gizmos.color = Color.cyan;
|
||||
// Gizmos.DrawCube(transform.parent.TransformPoint(ChamberRoundPosition), new Vector3(.025f, .025f, .025f));
|
||||
//}
|
||||
}
|
||||
|
||||
public enum HVRCockingHandleType
|
||||
{
|
||||
Reciprocating, NonReciprocating, Pump
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user