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.
		
		
		
		
		
			
		
			
				
	
	
		
			288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
using UnityEngine;
 | 
						|
using UnityEngine.Events;
 | 
						|
 | 
						|
namespace Autohand {
 | 
						|
    public delegate void StabEvent(Stabber stabber, Stabbable stab);
 | 
						|
 | 
						|
    [HelpURL("https://app.gitbook.com/s/5zKO0EvOjzUDeT2aiFk3/auto-hand/extras/stabbing")]
 | 
						|
    public class Stabber : MonoBehaviour {
 | 
						|
        [Tooltip("Can be left empty/null")]
 | 
						|
        public Grabbable grabbable;
 | 
						|
        [Header("Stab Settings")]
 | 
						|
        public CapsuleCollider stabCapsule;
 | 
						|
        [Tooltip("If left empty, will default to grabbable layers")]
 | 
						|
        public LayerMask stabbableLayers;
 | 
						|
        [Tooltip("The index that must match the stabbables index to allow stabbing")]
 | 
						|
        public int stabIndex;
 | 
						|
        public int maxStabs = 3;
 | 
						|
 | 
						|
 | 
						|
        [Header("Joint Settings")]
 | 
						|
        public Vector3 axis;
 | 
						|
        public float limit = float.MaxValue;
 | 
						|
        public ConfigurableJointMotion xMotion;
 | 
						|
        public ConfigurableJointMotion yMotion;
 | 
						|
        public ConfigurableJointMotion zMotion;
 | 
						|
        public ConfigurableJointMotion angularXMotion;
 | 
						|
        public ConfigurableJointMotion angularYMotion;
 | 
						|
        public ConfigurableJointMotion angularZMotion;
 | 
						|
        [Space]
 | 
						|
        public float positionDampeningMultiplyer = 1;
 | 
						|
        public float rotationDampeningMultiplyer = 1;
 | 
						|
 | 
						|
        [Header("Events")]
 | 
						|
        public UnityEvent StartStab;
 | 
						|
        public UnityEvent EndStab;
 | 
						|
 | 
						|
        //Progammer Events <3
 | 
						|
        public StabEvent StartStabEvent;
 | 
						|
        public StabEvent EndStabEvent;
 | 
						|
 | 
						|
        public List<Stabbable> stabbed { get; private set; }
 | 
						|
        public List<ConfigurableJoint> stabbedJoints { get; private set; }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        /// <summary>Helps prevent stabbable from being triggered accidently from the wrong angle</summary>
 | 
						|
        Dictionary<Stabbable, int> stabbedFrames;
 | 
						|
        const int STABFRAMES = 2;
 | 
						|
        int frames;
 | 
						|
 | 
						|
        Vector3 startPos;
 | 
						|
        Quaternion startRot;
 | 
						|
 | 
						|
        Vector3 lastPos;
 | 
						|
        Quaternion lastRot;
 | 
						|
        Collider[] resultsNonAlloc;
 | 
						|
 | 
						|
        Transform prereleaseParent;
 | 
						|
 | 
						|
        void Start() {
 | 
						|
            stabbedFrames = new Dictionary<Stabbable, int>();
 | 
						|
            stabbed = new List<Stabbable>();
 | 
						|
            stabbedJoints = new List<ConfigurableJoint>();
 | 
						|
            resultsNonAlloc = new Collider[25];
 | 
						|
            if(stabbableLayers == 0)
 | 
						|
                stabbableLayers = LayerMask.GetMask(Hand.grabbableLayers);
 | 
						|
 | 
						|
            if(grabbable == null)
 | 
						|
                gameObject.HasGrabbable(out grabbable);
 | 
						|
 | 
						|
            startPos = transform.position;
 | 
						|
            startRot = transform.rotation;
 | 
						|
 | 
						|
            StartCoroutine(StartWait());
 | 
						|
        }
 | 
						|
 | 
						|
        //This will keep the stabbables in place for the start stab
 | 
						|
        IEnumerator StartWait() {
 | 
						|
            for(int i = 0; i < STABFRAMES; i++) {
 | 
						|
                transform.position = startPos;
 | 
						|
                transform.rotation = startRot;
 | 
						|
                yield return new WaitForFixedUpdate();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private void FixedUpdate() {
 | 
						|
            if(transform.position != lastPos || lastRot != transform.rotation) {
 | 
						|
                frames = 0;
 | 
						|
                lastPos = transform.position;
 | 
						|
                lastRot = transform.rotation;
 | 
						|
            }
 | 
						|
            if(frames < STABFRAMES) {
 | 
						|
                CheckStabArea();
 | 
						|
                frames++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        protected virtual void CheckStabArea() {
 | 
						|
            Vector3 point1;
 | 
						|
            Vector3 point2;
 | 
						|
            Vector3 capsuleAxis;
 | 
						|
            var height = stabCapsule.height;
 | 
						|
            var radius = stabCapsule.radius;
 | 
						|
 | 
						|
            if(stabCapsule.direction == 0) {
 | 
						|
                capsuleAxis = Vector3.right;
 | 
						|
                height *= stabCapsule.transform.lossyScale.x;
 | 
						|
                radius *= stabCapsule.transform.lossyScale.y > stabCapsule.transform.lossyScale.z ? stabCapsule.transform.lossyScale.y : stabCapsule.transform.lossyScale.z;
 | 
						|
            }
 | 
						|
            else if(stabCapsule.direction == 1) {
 | 
						|
                capsuleAxis = Vector3.up;
 | 
						|
                height *= stabCapsule.transform.lossyScale.y;
 | 
						|
                radius *= stabCapsule.transform.lossyScale.z > stabCapsule.transform.lossyScale.x ? stabCapsule.transform.lossyScale.z : stabCapsule.transform.lossyScale.x;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                capsuleAxis = Vector3.forward;
 | 
						|
                height *= stabCapsule.transform.lossyScale.z;
 | 
						|
                radius *= stabCapsule.transform.lossyScale.y > stabCapsule.transform.lossyScale.x ? stabCapsule.transform.lossyScale.y : stabCapsule.transform.lossyScale.x;
 | 
						|
            }
 | 
						|
 | 
						|
            if(height / 2 <= radius) {
 | 
						|
                height = 0;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                height /= 2;
 | 
						|
                height -= radius;
 | 
						|
            }
 | 
						|
 | 
						|
            point1 = stabCapsule.bounds.center + stabCapsule.transform.rotation * capsuleAxis * (height);
 | 
						|
            point2 = stabCapsule.bounds.center - stabCapsule.transform.rotation * capsuleAxis * (height);
 | 
						|
            Physics.OverlapCapsuleNonAlloc(point1, point2, radius, resultsNonAlloc, stabbableLayers, QueryTriggerInteraction.Ignore);
 | 
						|
 | 
						|
            List<Stabbable> newStabbed = new List<Stabbable>();
 | 
						|
 | 
						|
            for(int i = 0; i < resultsNonAlloc.Length; i++) {
 | 
						|
                Stabbable tempStab;
 | 
						|
                if(resultsNonAlloc[i] != null) {
 | 
						|
                    if(resultsNonAlloc[i].CanGetComponent(out tempStab))
 | 
						|
                        if(tempStab.gameObject != gameObject)
 | 
						|
                            newStabbed.Add(tempStab);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            for(int i = stabbed.Count - 1; i >= 0; i--)
 | 
						|
                if(!newStabbed.Contains(stabbed[i]))
 | 
						|
                    OnStabbableExit(stabbed[i]);
 | 
						|
 | 
						|
            if(stabbed.Count < maxStabs)
 | 
						|
                for(int i = 0; i < newStabbed.Count; i++)
 | 
						|
                    if(!stabbed.Contains(newStabbed[i]) && newStabbed[i].CanStab(this))
 | 
						|
                        OnStabbableEnter(newStabbed[i]);
 | 
						|
 | 
						|
            for(int i = 0; i < resultsNonAlloc.Length; i++)
 | 
						|
                resultsNonAlloc[i] = null;
 | 
						|
 | 
						|
            if(stabbedFrames.Count > 0) {
 | 
						|
                var stabFrameKeys = new Stabbable[stabbedFrames.Count];
 | 
						|
                stabbedFrames.Keys.CopyTo(stabFrameKeys, 0);
 | 
						|
                foreach(var stabFrame in stabFrameKeys)
 | 
						|
                    if(!stabbed.Contains(stabFrame) && !newStabbed.Contains(stabFrame))
 | 
						|
                        stabbedFrames.Remove(stabFrame);
 | 
						|
            }
 | 
						|
 | 
						|
            newStabbed.Clear();
 | 
						|
        }
 | 
						|
 | 
						|
        protected virtual void OnStabbableEnter(Stabbable stab) {
 | 
						|
            if(stabbedFrames.ContainsKey(stab))
 | 
						|
                stabbedFrames[stab]++;
 | 
						|
            else
 | 
						|
                stabbedFrames.Add(stab, 1);
 | 
						|
 | 
						|
            if(stabbedFrames[stab] < STABFRAMES)
 | 
						|
                return;
 | 
						|
 | 
						|
            stabbed.Add(stab);
 | 
						|
            var joint = gameObject.AddComponent<ConfigurableJoint>();
 | 
						|
            joint.secondaryAxis = axis;
 | 
						|
            joint.connectedBody = stab.body;
 | 
						|
            joint.xMotion = xMotion;
 | 
						|
            joint.yMotion = yMotion;
 | 
						|
            joint.zMotion = zMotion;
 | 
						|
            joint.angularXMotion = angularXMotion;
 | 
						|
            joint.angularYMotion = angularYMotion;
 | 
						|
            joint.angularZMotion = angularZMotion;
 | 
						|
 | 
						|
            joint.linearLimit = new SoftJointLimit() { limit = this.limit };
 | 
						|
            joint.linearLimitSpring = new SoftJointLimitSpring() { damper = stab.positionDamper * positionDampeningMultiplyer };
 | 
						|
            joint.xDrive = new JointDrive() { positionDamper = stab.positionDamper * positionDampeningMultiplyer, maximumForce = float.MaxValue };
 | 
						|
            joint.yDrive = new JointDrive() { positionDamper = stab.positionDamper * positionDampeningMultiplyer, maximumForce = float.MaxValue };
 | 
						|
            joint.zDrive = new JointDrive() { positionDamper = stab.positionDamper * positionDampeningMultiplyer, maximumForce = float.MaxValue };
 | 
						|
            joint.slerpDrive = new JointDrive() { positionDamper = stab.positionDamper * positionDampeningMultiplyer };
 | 
						|
 | 
						|
            joint.angularXLimitSpring = new SoftJointLimitSpring() { damper = stab.rotationDamper * rotationDampeningMultiplyer };
 | 
						|
            joint.angularYZLimitSpring = new SoftJointLimitSpring() { damper = stab.rotationDamper * rotationDampeningMultiplyer };
 | 
						|
            joint.angularXDrive = new JointDrive() { positionDamper = stab.rotationDamper * rotationDampeningMultiplyer, maximumForce = float.MaxValue };
 | 
						|
            joint.angularYZDrive = new JointDrive() { positionDamper = stab.rotationDamper * rotationDampeningMultiplyer, maximumForce = float.MaxValue };
 | 
						|
            joint.projectionDistance /= 4f;
 | 
						|
 | 
						|
            joint.enablePreprocessing = true;
 | 
						|
            joint.enableCollision = false;
 | 
						|
 | 
						|
            Rigidbody jointBody;
 | 
						|
            joint.CanGetComponent(out jointBody);
 | 
						|
 | 
						|
            //resets the joint / wakes the body
 | 
						|
            jointBody.detectCollisions = false;
 | 
						|
            jointBody.detectCollisions = true;
 | 
						|
            stab.body.WakeUp();
 | 
						|
            jointBody.WakeUp();
 | 
						|
 | 
						|
            if(stab.parentOnStab && grabbable) {
 | 
						|
                grabbable.AddJointedBody(stab.body);
 | 
						|
            }
 | 
						|
            stabbedJoints.Add(joint);
 | 
						|
            stab.OnStab(this);
 | 
						|
            StartStabEvent?.Invoke(this, stab);
 | 
						|
            StartStab?.Invoke();
 | 
						|
        }
 | 
						|
 | 
						|
        protected virtual void OnStabbableExit(Stabbable stab) {
 | 
						|
            var removeIndex = stabbed.IndexOf(stab);
 | 
						|
            stabbed.Remove(stab);
 | 
						|
            var joint = stabbedJoints[removeIndex];
 | 
						|
            stabbedJoints.RemoveAt(removeIndex);
 | 
						|
            Destroy(joint);
 | 
						|
            if(stab.parentOnStab && grabbable) {
 | 
						|
                grabbable.RemoveJointedBody(stab.body);
 | 
						|
            }
 | 
						|
            stab.OnEndStab(this);
 | 
						|
            stabbedFrames.Remove(stab);
 | 
						|
            EndStabEvent?.Invoke(this, stab);
 | 
						|
            EndStab?.Invoke();
 | 
						|
        }
 | 
						|
 | 
						|
        public List<Stabbable> GetStabbed() {
 | 
						|
            return stabbed;
 | 
						|
        }
 | 
						|
 | 
						|
        public int GetStabbedCount() {
 | 
						|
            return stabbed.Count;
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        void OnDrawGizmosSelected() {
 | 
						|
            Vector3 point1;
 | 
						|
            Vector3 point2;
 | 
						|
            Vector3 capsuleAxis;
 | 
						|
            var height = stabCapsule.height;
 | 
						|
            var radius = stabCapsule.radius;
 | 
						|
 | 
						|
            if(stabCapsule.direction == 0) {
 | 
						|
                capsuleAxis = Vector3.right;
 | 
						|
                height *= stabCapsule.transform.lossyScale.x;
 | 
						|
                radius *= stabCapsule.transform.lossyScale.y > stabCapsule.transform.lossyScale.z ? stabCapsule.transform.lossyScale.y : stabCapsule.transform.lossyScale.z;
 | 
						|
            }
 | 
						|
            else if(stabCapsule.direction == 1) {
 | 
						|
                capsuleAxis = Vector3.up;
 | 
						|
                height *= stabCapsule.transform.lossyScale.y;
 | 
						|
                radius *= stabCapsule.transform.lossyScale.z > stabCapsule.transform.lossyScale.x ? stabCapsule.transform.lossyScale.z : stabCapsule.transform.lossyScale.x;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                capsuleAxis = Vector3.forward;
 | 
						|
                height *= stabCapsule.transform.lossyScale.z;
 | 
						|
                radius *= stabCapsule.transform.lossyScale.y > stabCapsule.transform.lossyScale.x ? stabCapsule.transform.lossyScale.y : stabCapsule.transform.lossyScale.x;
 | 
						|
            }
 | 
						|
 | 
						|
            if(height / 2 <= radius) {
 | 
						|
                height = 0;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                height /= 2;
 | 
						|
                height -= radius;
 | 
						|
            }
 | 
						|
 | 
						|
            point1 = stabCapsule.bounds.center + stabCapsule.transform.rotation * capsuleAxis * (height);
 | 
						|
            point2 = stabCapsule.bounds.center - stabCapsule.transform.rotation * capsuleAxis * (height);
 | 
						|
 | 
						|
            Gizmos.color = Color.blue;
 | 
						|
            Gizmos.DrawSphere(point1, radius);
 | 
						|
            Gizmos.DrawSphere(point2, radius);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |