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.
		
		
		
		
		
			
		
			
	
	
		
			208 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C#
		
	
		
		
			
		
	
	
			208 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C#
		
	
| 
								 
											1 year ago
										 
									 | 
							
								using System;
							 | 
						||
| 
								 | 
							
								using System.Collections;
							 | 
						||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						||
| 
								 | 
							
								using UnityEngine;
							 | 
						||
| 
								 | 
							
								using UnityEngine.Events;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace Autohand {
							 | 
						||
| 
								 | 
							
								    public enum SlideLoadType {
							 | 
						||
| 
								 | 
							
								        HandLoaded,
							 | 
						||
| 
								 | 
							
								        ShotLoaded
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [Serializable] public class UnityGunHitEvent : UnityEvent<AutoGun, RaycastHit> { }
							 | 
						||
| 
								 | 
							
								    [Serializable] public class UnityGunEvent : UnityEvent<AutoGun> { }
							 | 
						||
| 
								 | 
							
								    [Serializable] public class UnityGunSlideEvent : UnityEvent<AutoGun, SlideLoadType> { }
							 | 
						||
| 
								 | 
							
								    [Serializable] public class UnityAmmoEvent : UnityEvent<AutoGun, AutoAmmo> { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    [RequireComponent(typeof(Grabbable))]
							 | 
						||
| 
								 | 
							
								    public class AutoGun : MonoBehaviour {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [AutoHeader("Auto Gun")]
							 | 
						||
| 
								 | 
							
								        public bool ignoreMe1;
							 | 
						||
| 
								 | 
							
								        [Tooltip("The local forward of this transform is where the bullet raycast will come from")]
							 | 
						||
| 
								 | 
							
								        public Transform shootForward;
							 | 
						||
| 
								 | 
							
								        [Tooltip("(Optional) GrabbableHeldJoint recommended for triggering the LoadSlide event, if connected this will trigger the slide movement when shooting ")]
							 | 
						||
| 
								 | 
							
								        public GrabbableHeldJoint slideJoint;
							 | 
						||
| 
								 | 
							
								        [Tooltip("The place point for the ammo")]
							 | 
						||
| 
								 | 
							
								        public PlacePoint magazinePoint;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [AutoSmallHeader("Gun Settings")]
							 | 
						||
| 
								 | 
							
								        public bool ignoreMe2;
							 | 
						||
| 
								 | 
							
								        [Tooltip("The automatic fire rate while holding the trigger, 0 is semi-automatic")]
							 | 
						||
| 
								 | 
							
								        public float automaticFireRate = 0;
							 | 
						||
| 
								 | 
							
								        [Tooltip("The force applied to the target's rigidbody when hit")]
							 | 
						||
| 
								 | 
							
								        public float hitForce = 2500f;
							 | 
						||
| 
								 | 
							
								        [Tooltip("The force applied to the gun when shooting")]
							 | 
						||
| 
								 | 
							
								        public float recoilForce = 500f;
							 | 
						||
| 
								 | 
							
								        [Tooltip("The maximum distance a target can be hit")]
							 | 
						||
| 
								 | 
							
								        public float maxHitDistance = 1000f;
							 | 
						||
| 
								 | 
							
								        [Tooltip("If true the gun will hit every target until it hits a static collider")]
							 | 
						||
| 
								 | 
							
								        public bool useBulletPenetration = false;
							 | 
						||
| 
								 | 
							
								        [Tooltip("Whether or not the LoadSlide function needs to be called externally or if it is automatically called when the ammo is loaded")]
							 | 
						||
| 
								 | 
							
								        public bool requireSlideLoading = true;
							 | 
						||
| 
								 | 
							
								        [Tooltip("Whether or not the ammo clip should automatically be removed from the place point when it's empty")]
							 | 
						||
| 
								 | 
							
								        public bool autoEjectEmptyClip = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [AutoSmallHeader("Events")]
							 | 
						||
| 
								 | 
							
								        public bool ignoreMe5;
							 | 
						||
| 
								 | 
							
								        public UnityGunEvent OnShoot;
							 | 
						||
| 
								 | 
							
								        public UnityGunEvent OnEmptyShoot;
							 | 
						||
| 
								 | 
							
								        public UnityGunHitEvent OnHitEvent;
							 | 
						||
| 
								 | 
							
								        public UnityAmmoEvent OnAmmoPlaceEvent;
							 | 
						||
| 
								 | 
							
								        public UnityAmmoEvent OnAmmoRemoveEvent;
							 | 
						||
| 
								 | 
							
								        public UnityGunSlideEvent OnSlideEvent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected AutoAmmo loadedAmmo;
							 | 
						||
| 
								 | 
							
								        internal Grabbable grabbable;
							 | 
						||
| 
								 | 
							
								        protected bool slideLoaded = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        float lastFireTime;
							 | 
						||
| 
								 | 
							
								        bool squeezingTrigger;
							 | 
						||
| 
								 | 
							
								        bool lastSqueezingTrigger;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void Start() {
							 | 
						||
| 
								 | 
							
								            grabbable = GetComponent<Grabbable>();
							 | 
						||
| 
								 | 
							
								            if(magazinePoint != null)
							 | 
						||
| 
								 | 
							
								                magazinePoint.dontAllows.Add(grabbable);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void OnEnable() {
							 | 
						||
| 
								 | 
							
								            if(magazinePoint != null) {
							 | 
						||
| 
								 | 
							
								                magazinePoint.OnPlaceEvent += OnMagPlace;
							 | 
						||
| 
								 | 
							
								                magazinePoint.OnRemoveEvent += OnMagRemove;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        private void OnDisable() {
							 | 
						||
| 
								 | 
							
								            if(magazinePoint != null) {
							 | 
						||
| 
								 | 
							
								                magazinePoint.OnPlaceEvent -= OnMagPlace;
							 | 
						||
| 
								 | 
							
								                magazinePoint.OnRemoveEvent -= OnMagRemove;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void FixedUpdate() {
							 | 
						||
| 
								 | 
							
								            if(squeezingTrigger && automaticFireRate > 0 && slideLoaded && Time.fixedTime-lastFireTime > automaticFireRate)
							 | 
						||
| 
								 | 
							
								                Shoot();
							 | 
						||
| 
								 | 
							
								            else if(squeezingTrigger && !lastSqueezingTrigger && automaticFireRate <= 0)
							 | 
						||
| 
								 | 
							
								                Shoot();
							 | 
						||
| 
								 | 
							
								            else if(squeezingTrigger && !lastSqueezingTrigger && automaticFireRate > 0)
							 | 
						||
| 
								 | 
							
								                Shoot();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            lastSqueezingTrigger = squeezingTrigger;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void PressTrigger() {
							 | 
						||
| 
								 | 
							
								            squeezingTrigger = true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void ReleaseTrigger() {
							 | 
						||
| 
								 | 
							
								            squeezingTrigger = false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void Shoot() {
							 | 
						||
| 
								 | 
							
								            if(slideLoaded) {
							 | 
						||
| 
								 | 
							
								                grabbable.body.AddForceAtPosition(-shootForward.forward * recoilForce / 10f, shootForward.position);
							 | 
						||
| 
								 | 
							
								                grabbable.body.AddForceAtPosition(shootForward.up * recoilForce, shootForward.position);
							 | 
						||
| 
								 | 
							
								                OnShoot?.Invoke(this);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if(useBulletPenetration){
							 | 
						||
| 
								 | 
							
								                    var raycasthits = Physics.RaycastAll(shootForward.position, shootForward.forward, maxHitDistance, ~0, QueryTriggerInteraction.Ignore);
							 | 
						||
| 
								 | 
							
								                    if(raycasthits.Length > 0) {
							 | 
						||
| 
								 | 
							
								                        foreach(var hit in raycasthits) {
							 | 
						||
| 
								 | 
							
								                            if(hit.rigidbody != grabbable.body)
							 | 
						||
| 
								 | 
							
								                                OnHit(hit);
							 | 
						||
| 
								 | 
							
								                            if(hit.rigidbody == null)
							 | 
						||
| 
								 | 
							
								                                break;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else if(Physics.Raycast(shootForward.position, shootForward.forward, out var hit, maxHitDistance, ~0, QueryTriggerInteraction.Ignore)){
							 | 
						||
| 
								 | 
							
								                    if(hit.rigidbody != grabbable.body)
							 | 
						||
| 
								 | 
							
								                        OnHit(hit);
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                        Debug.LogError("Gun is shooting itself, make sure the shootforward transform is not inside a collider", this);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                lastFireTime = Time.fixedTime;
							 | 
						||
| 
								 | 
							
								                FireLoadSlide();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								                OnEmptyShoot?.Invoke(this);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if(autoEjectEmptyClip && loadedAmmo != null && loadedAmmo.currentAmmo == 0 && !slideLoaded)
							 | 
						||
| 
								 | 
							
								                magazinePoint?.Remove();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void LoadSlide() {
							 | 
						||
| 
								 | 
							
								            OnSlideEvent?.Invoke(this, SlideLoadType.HandLoaded);
							 | 
						||
| 
								 | 
							
								            slideLoaded = loadedAmmo != null && loadedAmmo.currentAmmo > 0;
							 | 
						||
| 
								 | 
							
								            if(slideLoaded)
							 | 
						||
| 
								 | 
							
								                loadedAmmo.RemoveAmmo();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void FireLoadSlide() {
							 | 
						||
| 
								 | 
							
								            OnSlideEvent?.Invoke(this, SlideLoadType.ShotLoaded);
							 | 
						||
| 
								 | 
							
								            slideLoaded = loadedAmmo != null && loadedAmmo.currentAmmo > 0;
							 | 
						||
| 
								 | 
							
								            if(slideLoaded)
							 | 
						||
| 
								 | 
							
								                loadedAmmo.RemoveAmmo();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void UnloadSlide() {
							 | 
						||
| 
								 | 
							
								            slideLoaded = false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public bool IsSlideLoaded() {
							 | 
						||
| 
								 | 
							
								            return slideLoaded;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>Returns ammo in count in current clip plus slide</summary>
							 | 
						||
| 
								 | 
							
								        public int GetAmmo() {
							 | 
						||
| 
								 | 
							
								            int ammo = slideLoaded ? 1 : 0;
							 | 
						||
| 
								 | 
							
								            if(loadedAmmo != null)
							 | 
						||
| 
								 | 
							
								                ammo += loadedAmmo.currentAmmo;
							 | 
						||
| 
								 | 
							
								            return magazinePoint == null ? 1 : ammo;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        void OnMagPlace(PlacePoint point, Grabbable mag) {
							 | 
						||
| 
								 | 
							
								            if(mag.TryGetComponent<AutoAmmo>(out var ammo)) {
							 | 
						||
| 
								 | 
							
								                this.loadedAmmo = ammo;
							 | 
						||
| 
								 | 
							
								                OnAmmoPlaceEvent?.Invoke(this, loadedAmmo);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            if(!slideLoaded && !requireSlideLoading)
							 | 
						||
| 
								 | 
							
								                LoadSlide();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        void OnMagRemove(PlacePoint point, Grabbable mag) {
							 | 
						||
| 
								 | 
							
								            OnAmmoRemoveEvent?.Invoke(this, loadedAmmo);
							 | 
						||
| 
								 | 
							
								            loadedAmmo = null;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        protected virtual void OnHit(RaycastHit hit) {
							 | 
						||
| 
								 | 
							
								            if(hit.rigidbody) {
							 | 
						||
| 
								 | 
							
								                hit.rigidbody.AddForceAtPosition(shootForward.forward * recoilForce, hit.point);
							 | 
						||
| 
								 | 
							
								                OnHitEvent?.Invoke(this, hit);
							 | 
						||
| 
								 | 
							
								                if(hit.rigidbody.TryGetComponent<AutoGunTarget>(out var target))
							 | 
						||
| 
								 | 
							
								                    target.OnShot(this, hit);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |