// GDnD wiki example // Demonstrates: Reynolds-style steering — seek the player plus separation from neighbours // Related pages: [[overview-arcade-classics-as-learning-projects]], [[steering-behaviours]] using UnityEngine; // The enemy hunts the player with two classic steering behaviours added together: // SEEK (accelerate toward the target) and SEPARATION (push away from nearby // enemies so the swarm spreads instead of stacking). This is the same vector // approach as the Asteroids ship, now used for AI — see [[steering-behaviours]]. public class Enemy : MonoBehaviour { [SerializeField] private float maxSpeed = 3.5f; [SerializeField] private float maxForce = 8f; [SerializeField] private float separationRadius = 0.7f; [SerializeField] private float separationWeight = 1.5f; [Tooltip("The enemy layer, used to find neighbours for separation.")] [SerializeField] private LayerMask enemyMask; private RobotronGame game; private Transform target; private Vector2 velocity; public void Init(RobotronGame owner, Transform player) { game = owner; target = player; } private void Update() { if (target == null) { return; } Vector2 steer = Seek((Vector2)target.position) + Separation() * separationWeight; velocity = Vector2.ClampMagnitude(velocity + steer * Time.deltaTime, maxSpeed); transform.position += (Vector3)(velocity * Time.deltaTime); } // Steer toward a target: desired velocity minus current velocity, force-limited. private Vector2 Seek(Vector2 targetPosition) { Vector2 desired = (targetPosition - (Vector2)transform.position).normalized * maxSpeed; return Vector2.ClampMagnitude(desired - velocity, maxForce); } // Steer away from the average direction of nearby enemies. private Vector2 Separation() { Collider2D[] neighbours = Physics2D.OverlapCircleAll(transform.position, separationRadius, enemyMask); Vector2 sum = Vector2.zero; int count = 0; foreach (Collider2D neighbour in neighbours) { if (neighbour.gameObject == gameObject) { continue; } Vector2 away = (Vector2)(transform.position - neighbour.transform.position); float distance = away.magnitude; if (distance > 0f) { sum += away.normalized / distance; // closer neighbours push harder count++; } } if (count == 0) { return Vector2.zero; } Vector2 desired = (sum / count).normalized * maxSpeed; return Vector2.ClampMagnitude(desired - velocity, maxForce); } public void Hit() { game?.OnEnemyKilled(this); } }