using System; using System.Collections; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.Events; // ReSharper disable once CheckNamespace namespace BlueWaterProject { public class ParticleWeapon : MonoBehaviour { public GameObject impactParticle; // Effect spawned when projectile hits a collider public GameObject projectileParticle; // Effect attached to the gameobject as child public GameObject muzzleParticle; // Effect instantly spawned when gameobject is spawned [Header("Adjust if not using Sphere Collider")] public float colliderRadius = 1f; [Range(0f, 1f)] // This is an offset that moves the impact effect slightly away from the point of impact to reduce clipping of the impact effect public float collideOffset = 0.15f; [Title("Extensions Data")] [SerializeField] private LayerMask targetLayer; [SerializeField] private bool useAutoDestroy = true; [ShowIf("@useAutoDestroy")] [SerializeField] private float autoDestroyTime = 5f; public UnityEvent onHitAction; private float power; private float detectionDistance; private Rigidbody rb; private SphereCollider sphereCollider; private void OnDrawGizmosSelected() { var radius = sphereCollider ? sphereCollider.radius : colliderRadius; var direction = rb ? rb.velocity.normalized : transform.forward; Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, radius); // Draws the start sphere Gizmos.DrawLine(transform.position, transform.position + direction * detectionDistance); // Draws the path of the SphereCast } private void Awake() { rb = GetComponent(); sphereCollider = GetComponent(); } private void Start() { if (useAutoDestroy) { Destroy(gameObject, autoDestroyTime); } projectileParticle = Instantiate(projectileParticle, transform.position, transform.rotation) as GameObject; projectileParticle.transform.parent = transform; if (muzzleParticle) { muzzleParticle = Instantiate(muzzleParticle, transform.position, transform.rotation) as GameObject; Destroy(muzzleParticle, 1.5f); // 2nd parameter is lifetime of effect in seconds } } private void FixedUpdate() { if (rb.velocity.magnitude != 0) { transform.rotation = Quaternion.LookRotation(rb.velocity); // Sets rotation to look at direction of movement } float radius; // Sets the radius of the collision detection if (sphereCollider) radius = sphereCollider.radius; else radius = colliderRadius; var direction = rb.velocity; // Gets the direction of the projectile, used for collision detection if (rb.useGravity) direction += Physics.gravity * Time.deltaTime; // Accounts for gravity if enabled direction = direction.normalized; detectionDistance = rb.velocity.magnitude * Time.deltaTime; // Distance of collision detection for this frame if (Physics.SphereCast(transform.position, radius, direction, out var hit, detectionDistance, targetLayer)) // Checks if collision will happen { transform.position = hit.point + (hit.normal * collideOffset); // Move projectile to point of collision var impactP = Instantiate(impactParticle, transform.position, Quaternion.FromToRotation(Vector3.up, hit.normal)) as GameObject; // Spawns impact effect var trails = GetComponentsInChildren(); // Gets a list of particle systems, as we need to detach the trails //Component at [0] is that of the parent i.e. this object (if there is any) for (var i = 1; i < trails.Length; i++) // Loop to cycle through found particle systems { var trail = trails[i]; if (trail.gameObject.name.Contains("Trail")) { trail.transform.SetParent(null); // Detaches the trail from the projectile Destroy(trail.gameObject, 2f); // Removes the trail after seconds } } if (onHitAction == null) { hit.transform.GetComponent()?.TakeDamage(power); } else { onHitAction.Invoke(hit, power); } Destroy(projectileParticle, 3f); // Removes particle effect after delay Destroy(impactP, 3.5f); // Removes impact effect after delay Destroy(gameObject); // Removes the projectile } } public void SetPower(float value) => power = value; } }