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#
		
	
			
		
		
	
	
			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;
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
} |