A modular AI framework built in Unity (C#) featuring steering behaviours, flocking systems, utility-based decision making, and multiple pathfinding algorithms. Designed with extensibility, performance, and debugging clarity in mind.
Role: Gameplay / AI Programmer
Engine: Unity (C#)
Built a composable steering framework where behaviours calculate forces independently and blend via weighted accumulation.
Implemented Alignment, Cohesion, and Separation using spatial queries, field-of-view filtering, and weighted steering forces.
Designed a scalable utility system allowing agents to dynamically prioritise combat, support, flee, and exploration behaviours.
Implemented Dijkstra, A*, and Jump Point Search (JPS) with diagonal control and heuristic configuration.
Velocity-scaled whisker raycasts detect penetration depth and apply corrective steering forces with debug visualisation.
Integrated Gizmos and grid colouring for live inspection of steering, obstacle detection, and path expansion.
Core movement system where each behaviour computes a steering force and blends into the final velocity.
All behaviours calculate a desired velocity and subtract the current velocity to produce a steering force. Forces are weight-scaled and blended.
// Steering formula
Vector2 steering = desiredVelocity - currentVelocity;
return steering * weight;
This structure allows behaviours to be enabled/disabled dynamically by higher-level AI systems.
Implemented Reynolds-style flocking using physics queries, dot-product FOV filtering, and inverse-distance weighting.
Agents average neighbour headings and steer toward the combined direction to maintain group coherence.
Agents calculate the centre of mass of nearby neighbours and apply a seek force toward that position.
Repulsion force is calculated using inverse-distance weighting to prevent overlap and jitter while preserving smooth motion.
// Neighbour detection
Collider2D[] agents =
Physics2D.OverlapCircleAll(transform.position, range, agentLayerMask);
Velocity-scaled feelers project forward to detect obstacles and compute penetration-based repulsion forces.
Feeler length interpolates based on current speed, allowing faster agents to anticipate collisions earlier.
// Raycast detection
RaycastHit2D hit =
Physics2D.Raycast(origin, direction, length, layerMask);
Debug colours visualise hit states directly in the editor.
Replaced rigid FSM transitions with dynamic utility scoring to allow emergent prioritisation.
Sense → Calculate Utilities → Choose Highest Score → Activate Steering.
// Utility selection
foreach (var pair in utilityDictionary)
{
if (pair.Value > bestScore)
currentState = pair.Key;
}
State cooldowns prevent oscillation and improve behavioural stability.
Implemented multiple grid-based pathfinding algorithms with configurable heuristics and diagonal rules.
Uniform cost expansion guaranteeing shortest path.
Combined gCost and heuristic (Manhattan / Octile) for optimal and efficient path resolution.
Directional pruning reduces node expansion by identifying forced neighbours and symmetric paths.
// Cheapest node selection
return nodes.OrderBy(n => n.fCost).First();