// GDnD wiki example // Demonstrates: a pooled, transform-driven bullet that hits a target layer and returns itself to the pool // Related pages: [[overview-arcade-classics-as-learning-projects]], [[object-pool-pattern]], [[unity-collider2d-and-triggers]] using UnityEngine; // Transform-driven like the rest of the series — no Rigidbody. The bullet moves // straight up or down, checks for a target on a given layer, and releases itself // back to the pool when it hits something or leaves the screen. public class Projectile : MonoBehaviour { [SerializeField] private Vector2 hitBoxSize = new Vector2(0.15f, 0.4f); private ProjectilePool pool; private float verticalDirection; private float speed; private LayerMask targetMask; private float halfSize; private Camera cachedCamera; private void Awake() { cachedCamera = Camera.main; halfSize = GetComponent().bounds.extents.y; } public void SetPool(ProjectilePool ownerPool) { pool = ownerPool; } // Aim it: +1 fires upward (player), -1 fires downward (invaders). public void Launch(Vector3 position, float direction, float launchSpeed, LayerMask mask) { transform.position = position; verticalDirection = Mathf.Sign(direction); speed = launchSpeed; targetMask = mask; } private void Update() { transform.position += Vector3.up * (verticalDirection * speed * Time.deltaTime); if (TryHitTarget() || IsOffScreen()) { pool.Release(this); } } private bool TryHitTarget() { Collider2D hit = Physics2D.OverlapBox(transform.position, hitBoxSize, 0f, targetMask); if (hit == null) { return false; } // Hit anything that knows how to be hit, without caring what it is. IHittable hittable = hit.GetComponent(); hittable?.Hit(); return true; } private bool IsOffScreen() { float topEdge = cachedCamera.orthographicSize + halfSize; return Mathf.Abs(transform.position.y) > topEdge; } }