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