using MegaKoop.Game.Combat; using UnityEngine; namespace MegaKoop.Game.WeaponSystem { public class Projectile : MonoBehaviour { [SerializeField] private float hitRadius = 0.05f; [SerializeField] private LayerMask hitMask = Physics.DefaultRaycastLayers; [SerializeField] private bool alignToVelocity = true; private Vector3 direction; private float speed; private float damage; private float lifetime; private float timeAlive; private Team sourceTeam; private GameObject owner; private Collider[] projectileColliders; public void Initialize(Vector3 shotDirection, float projectileSpeed, float damageAmount, float projectileLifetime, GameObject projectileOwner, Team ownerTeam, Collider[] ownerColliders, LayerMask mask) { direction = shotDirection.sqrMagnitude > 0f ? shotDirection.normalized : transform.forward; speed = Mathf.Max(0f, projectileSpeed); damage = Mathf.Max(0f, damageAmount); lifetime = Mathf.Max(0.01f, projectileLifetime); owner = projectileOwner; sourceTeam = ownerTeam; hitMask = mask; timeAlive = 0f; projectileColliders ??= GetComponentsInChildren(); if (ownerColliders != null && projectileColliders != null) { foreach (Collider ownerCollider in ownerColliders) { if (ownerCollider == null) { continue; } foreach (Collider projectileCollider in projectileColliders) { if (projectileCollider == null) { continue; } Physics.IgnoreCollision(projectileCollider, ownerCollider, true); } } } } private void Update() { float deltaTime = Time.deltaTime; Vector3 displacement = direction * speed * deltaTime; float distance = displacement.magnitude; if (distance > 0f) { if (Physics.SphereCast(transform.position, hitRadius, direction, out RaycastHit hitInfo, distance, hitMask, QueryTriggerInteraction.Ignore)) { TryHandleHit(hitInfo.collider, hitInfo.point, hitInfo.normal); return; } transform.position += displacement; } if (alignToVelocity && distance > 0f) { transform.forward = direction; } timeAlive += deltaTime; if (timeAlive >= lifetime) { Destroy(gameObject); } } private void OnTriggerEnter(Collider other) { TryHandleHit(other, transform.position, -direction); } private void TryHandleHit(Collider other, Vector3 hitPoint, Vector3 hitNormal) { if (other == null) { return; } if (owner != null) { if (other.transform.IsChildOf(owner.transform)) { return; } } IDamageable damageable = other.GetComponentInParent(); if (damageable != null && damageable.IsAlive) { bool isFriendly = damageable.Team == sourceTeam && damageable.Team != Team.Neutral; if (isFriendly) { return; } if (damage > 0f) { var payload = new DamagePayload(damage, hitPoint, hitNormal, owner, sourceTeam, other.gameObject); damageable.ApplyDamage(payload); } } Destroy(gameObject); } } }