Source file unity-csharp/arcade-classics/robotron-lite/Enemy.cs from the GDnD code examples. Download raw file
// 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);
}
}