You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
6.3 KiB
C#

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
namespace Autohand {
[Serializable, DefaultExecutionOrder(100)]
public class UnityDispenserEvent : UnityEvent<DispenserPoint, Grabbable> { }
public class DispenserPoint : MonoBehaviour {
[AutoHeader("Dispenser Point")]
public bool ignoreMe;
[AutoSmallHeader("Dispenser Settings")]
public bool showeSettings = true;
[Tooltip("The object to be copied and dispensed")]
public Grabbable dispenseObject;
[Tooltip("The maximum copies allowed to exist from this dispenser before they are destroyed or reset")]
public int maxCopies = 3;
[Tooltip("The delay in seconds before the next dispense appears after the current dispense is taken")]
public float resetDelay = 0f;
[Tooltip("Whether or not objects placed in the dispense point should be set to kinematic on placed or not")]
public bool disableBody = false;
[NaughtyAttributes.HideIf("disableBody"), Tooltip("Whether or not objects placed in the dispense point should be set to kinematic on placed or not")]
public bool isKinematic = true;
[Tooltip("If true the object will not just reset its position on reset it will be destroyed and a new copy will be placed. Less performant but important for things like ammo that should always respawn as new clips full")]
public bool destroyOnReset = false;
[Tooltip("The maximum distance a dispensed object can move from the point before the next object is dispensed")]
public float maxDistance = 1f;
[Space]
public UnityDispenserEvent OnGrabDispenseEvent;
public UnityDispenserEvent OnDispenseEvent;
Grabbable currentDispense;
Grabbable lastDispense;
GameObject[] dispensePool;
int poolCount;
Coroutine dispenseRoutine;
protected virtual void Start() {
GameObject instanceObject;
dispenseObject.body.gameObject.SetActive(false);
instanceObject = Instantiate(dispenseObject.body.gameObject);
instanceObject.transform.position = transform.position;
instanceObject.transform.rotation = transform.rotation;
instanceObject.SetActive(true);
dispensePool = new GameObject[maxCopies];
dispensePool[0] = instanceObject;
if(dispensePool[0].HasGrabbable(out var grab)) {
if(!disableBody && isKinematic && grab.body != null)
grab.body.isKinematic = true;
grab.OnGrabEvent += OnGrab;
grab.OnPlacePointAddEvent += OnPlaced;
currentDispense = grab;
if(disableBody)
grab.DeactivateRigidbody();
}
poolCount++;
}
protected virtual void OnDisable() {
if(dispenseRoutine != null)
StopCoroutine(dispenseRoutine);
dispenseRoutine = null;
}
protected virtual void FixedUpdate() {
if(maxDistance > 0 && currentDispense.gameObject.activeInHierarchy && Vector3.Distance(transform.position, currentDispense.rootTransform.position) > maxDistance)
Dispense();
}
public virtual Grabbable Dispense() {
if(dispenseRoutine == null) {
var poolIndex = (poolCount) % maxCopies;
if(destroyOnReset) {
Destroy(dispensePool[poolIndex]);
dispensePool[poolIndex] = null;
}
if(poolCount < maxCopies || dispensePool[poolIndex] == null || dispensePool[poolIndex].activeInHierarchy == false)
dispensePool[poolIndex] = Instantiate(dispenseObject.body.gameObject);
dispensePool[poolIndex].transform.position = transform.position;
dispensePool[poolIndex].transform.rotation = transform.rotation;
if(dispensePool[poolIndex].HasGrabbable(out var grab)) {
grab.ForceHandsRelease();
if(grab.placePoint != null)
grab.placePoint.Remove();
if(grab.body == null)
grab.ActivateRigidbody();
if(!disableBody && isKinematic)
grab.body.isKinematic = true;
if(!grab.body.isKinematic) {
grab.body.velocity = Vector3.zero;
grab.body.angularVelocity = Vector3.zero;
}
grab.OnGrabEvent += OnGrab;
grab.OnPlacePointAddEvent += OnPlaced;
dispenseRoutine = StartCoroutine(DispenseResetDelay(grab));
lastDispense = currentDispense;
lastDispense.OnGrabEvent -= OnGrab;
lastDispense.OnPlacePointAddEvent -= OnPlaced;
currentDispense = grab;
poolCount++;
return grab;
}
poolCount++;
}
return null;
}
public virtual void OnGrab(Hand hand, Grabbable grab) {
if(grab != null && isKinematic && grab.body != null)
grab.body.isKinematic = false;
OnGrabDispenseEvent?.Invoke(this, grab);
Dispense();
}
public virtual void OnPlaced(PlacePoint point, Grabbable grab) {
if(grab != null && isKinematic && grab.body != null)
grab.body.isKinematic = false;
Debug.Log("Placed: " + grab.body.isKinematic);
Dispense();
}
IEnumerator DispenseResetDelay(Grabbable dispenseObject) {
dispenseObject.body.gameObject.SetActive(false);
yield return new WaitForSeconds(resetDelay);
dispenseObject.body.gameObject.SetActive(true);
dispenseObject.IgnoreGrabbableCollisionUntilNone(lastDispense);
foreach(var hand in lastDispense.GetHeldBy())
dispenseObject.IgnoreHandCollisionUntilNone(hand);
OnDispenseEvent?.Invoke(this, dispenseObject);
if(disableBody)
dispenseObject.DeactivateRigidbody();
dispenseRoutine = null;
}
}
}