using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Autohand { [RequireComponent(typeof(AutoGun))] public class AutoGunEffects : MonoBehaviour { [AutoSmallHeader("Visual Effects")] public bool ignoreMe3; [Tooltip("Whether or not racking the slide with a bullet already in the chamber ejects that bullet or not")] public bool ejectUnfiredBullet = true; [Tooltip("This is the unfired bullet prefab that will be instantiated and ejected if the 'ejectUnfiredBullet' value is true and the slide is racked while full")] public GameObject bullet; [Tooltip("This is the fired bullet shell prefab that will be instantiated and ejected if the when the gun is shot")] public GameObject bulletShell; [Tooltip("Particle effect that plays from the gun aim transform on shoot")] public ParticleSystem shootParticle; [Tooltip("The lifetime of the ejected bullets before they are added to the pool")] public float ejectedBulletLifetime = 3f; [Tooltip("The position and rotation where the bullets are instantiated")] public Transform shellEjectionSpawnPoint; [Tooltip("The forward direction of this point represents the direction the shells should be ejected")] public Transform shellEjectionDirection; [Tooltip("The amount of force to add to the ejected bullet")] public float shellEjectionForce = 50; [AutoSmallHeader("Sound Effects")] public bool ignoreMe4; [Tooltip("This sound will play when a bullet is fired")] public AudioSource shootSound; [Tooltip("This sound will play when a the trigger is pressed and there is nothing to shoot")] public AudioSource emptyShootSound; Dictionary bulletLifetimeTracker = new Dictionary(); Dictionary shellLifetimeTracker = new Dictionary(); List bulletPool = new List(); List bulletShellPool = new List(); List activeParticlePool = new List(); List inactiveParticlePool = new List(); AutoGun gun; private void OnEnable(){ gun = GetComponent(); gun.OnShoot.AddListener(OnShoot); gun.OnEmptyShoot.AddListener(OnEmptyShoot); gun.OnSlideEvent.AddListener(OnSlideLoaded); } private void OnDisable(){ gun.OnShoot.RemoveListener(OnShoot); gun.OnEmptyShoot.RemoveListener(OnEmptyShoot); gun.OnSlideEvent.RemoveListener(OnSlideLoaded); } private void FixedUpdate() { CheckBulletLifetime(); CheckParticlPlaying(); } void CreateShootParticle() { if(shootParticle != null) { var newShootParticle = GameObject.Instantiate(shootParticle); newShootParticle.transform.position = gun.shootForward.position; newShootParticle.transform.forward = gun.shootForward.forward; activeParticlePool.Add(newShootParticle); } } void OnShoot(AutoGun gun){ shootSound?.PlayOneShot(shootSound.clip); CreateShootParticle(); } void OnEmptyShoot(AutoGun gun){ emptyShootSound?.PlayOneShot(emptyShootSound.clip); } void OnSlideLoaded(AutoGun gun, SlideLoadType loadType) { if(loadType == SlideLoadType.ShotLoaded){ if(gun.slideJoint != null) { if(Mathf.Abs(gun.slideJoint.xMinLimit) >= gun.slideJoint.xMaxLimit && Mathf.Abs(gun.slideJoint.yMinLimit) >= gun.slideJoint.yMaxLimit && Mathf.Abs(gun.slideJoint.zMinLimit) >= gun.slideJoint.zMaxLimit) gun.slideJoint.SetJointMin(); else gun.slideJoint.SetJointMax(); } EjectShell(); } else if(gun.IsSlideLoaded()) { EjectBullet(); } } public void EjectBullet() { if(bullet != null) { GameObject newBullet; if(bulletPool.Count > 0) { newBullet = bulletPool[0]; bulletPool.RemoveAt(0); newBullet.transform.position = shellEjectionSpawnPoint.position; newBullet.transform.rotation = shellEjectionSpawnPoint.rotation; newBullet.SetActive(true); } else { newBullet = Instantiate(bullet, shellEjectionSpawnPoint.position, shellEjectionSpawnPoint.rotation); } if(newBullet.CanGetComponent(out var body)) { if(AutoHandPlayer.Instance.IsHolding(gun.grabbable)) body.velocity = AutoHandPlayer.Instance.body.velocity; body.velocity += gun.grabbable.body.velocity; body.AddForce(shellEjectionDirection.forward * shellEjectionForce, ForceMode.Force); } bulletLifetimeTracker.Add(newBullet, ejectedBulletLifetime); } } public void EjectShell() { if(bulletShell != null) { GameObject newShell; if(bulletShellPool.Count > 0) { newShell = bulletShellPool[0]; bulletShellPool.RemoveAt(0); newShell.transform.position = shellEjectionSpawnPoint.position; newShell.transform.rotation = shellEjectionSpawnPoint.rotation; newShell.SetActive(true); } else { newShell = Instantiate(bulletShell, shellEjectionSpawnPoint.position, shellEjectionSpawnPoint.rotation); } if(newShell.CanGetComponent(out var body)) { if(AutoHandPlayer.Instance.IsHolding(gun.grabbable)) body.velocity = AutoHandPlayer.Instance.body.velocity; body.velocity += gun.grabbable.body.velocity; body.AddForce(shellEjectionDirection.forward * shellEjectionForce, ForceMode.Force); } shellLifetimeTracker.Add(newShell, ejectedBulletLifetime); } } void CheckBulletLifetime() { if(bulletLifetimeTracker.Count > 0) { var bulletKeys = new GameObject[bulletLifetimeTracker.Count]; bulletLifetimeTracker.Keys.CopyTo(bulletKeys, 0); foreach(var bullet in bulletKeys) { bulletLifetimeTracker[bullet] -= Time.deltaTime; if(bulletLifetimeTracker[bullet] <= 0) { bullet.SetActive(false); bulletPool.Add(bullet); bulletLifetimeTracker.Remove(bullet); } } } if(shellLifetimeTracker.Count > 0) { var shellKeys = new GameObject[shellLifetimeTracker.Count]; shellLifetimeTracker.Keys.CopyTo(shellKeys, 0); foreach(var shell in shellKeys) { shellLifetimeTracker[shell] -= Time.deltaTime; if(shellLifetimeTracker[shell] <= 0) { shell.SetActive(false); bulletShellPool.Add(shell); shellLifetimeTracker.Remove(shell); } } } } void CheckParticlPlaying() { if(inactiveParticlePool.Count > 0) { var playingKeys = new ParticleSystem[activeParticlePool.Count]; activeParticlePool.CopyTo(playingKeys, 0); foreach(var particle in playingKeys) { if(!particle.isPlaying) particle.gameObject.SetActive(false); inactiveParticlePool.Add(particle); activeParticlePool.Remove(particle); } } } } }