using System; using System.Collections.Generic; using UnityEngine; public class Bullet : Entity, IColliderChecker { [SerializeField] float speed = 10.0f; [SerializeField] float lifeTime = 5.0f; [SerializeField] float maxDistance = 0f; Vector2 headDirection; float flyingDistance = 0.0f; float elapsedLifeTime = 0.0f; HashSet collideFilter = new HashSet(); HashSet currentColliders = new HashSet(); public event Action OnBeforeDestroy; public event Action OnEnterCollider; public float Speed { get => speed; set => speed = value; } public Vector2 HeadDirection { get { if (headDirection == default) { float zRad = transform.eulerAngles.z * Mathf.Deg2Rad; headDirection = new Vector2(Mathf.Cos(zRad), Mathf.Sin(zRad)).normalized; } return headDirection; } set { headDirection = value.normalized; transform.eulerAngles = new Vector3(0, 0, Mathf.Atan2(value.y, value.x) * Mathf.Rad2Deg); } } public bool IsFired { get; private set; } = false; private void LateUpdate() { if (!IsFired) return; float moveUnit = speed * Time.fixedDeltaTime; bool shouldDestroy = !UpdateLifeTime(); shouldDestroy |= !UpdateFlyingDistance(moveUnit); if (shouldDestroy) { OnBeforeDestroy?.Invoke(this); Destroy(gameObject); } else { transform.position += (Vector3)HeadDirection * moveUnit; } } private bool UpdateLifeTime() { elapsedLifeTime += Time.fixedUnscaledDeltaTime; return elapsedLifeTime < lifeTime; } private bool UpdateFlyingDistance(float moveUnit) { if(flyingDistance <= 0) return true; flyingDistance += moveUnit; return flyingDistance < maxDistance; } public void Fire() { elapsedLifeTime = 0; flyingDistance = 0; IsFired = true; } public void Fire(Transform target) { HeadDirection = target.position - transform.position; elapsedLifeTime = 0; flyingDistance = 0; IsFired = true; } public void AddTagFilter(params string[] tags) => collideFilter.UnionWith(tags); public void RemoveTagFilter(params string[] tags) => collideFilter.ExceptWith(tags); public void ClearTagFilter() => collideFilter.Clear(); public void CheckColliding(Action collided) { foreach (var target in currentColliders) { collided.Invoke(target); } } private void OnTriggerEnter2D(Collider2D other) { if (collideFilter.Contains(other.tag)) { currentColliders.Add(other); OnEnterCollider?.Invoke(other); } } private void OnTriggerExit2D(Collider2D collision) { currentColliders.Remove(collision); } }