Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Readable unit formations in Unity need two separate systems: code that assigns every unit a distinct slot, and movement that carries each unit to its own slot. A NavMeshAgent handles an individual agent’s navigation; it does not generate a shared row, grid, wedge, or ring. Give each member a target derived from a common formation frame, then let the agent follow that target.

Why units bunch up around the leader

If every unit follows the player’s position, every agent receives the same destination. They may avoid occupying precisely the same space, but avoidance is not a formation layout: it does not assign stable places or preserve a deliberate silhouette. The remedy is to calculate a different target for each member.

Unity describes NavMeshAgent as a component for mobile characters that navigate a scene using a NavMesh. Its destination and path APIs operate on an individual agent; the formation slots described here are project code, not a built-in formation generator. See the Unity NavMesh Agent manual and NavMeshAgent scripting reference.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a layout that suits the camera and terrain

Begin with a row or grid: the slot math is easy to inspect, and the resulting spacing is predictable. A wedge or column can make direction of travel more apparent, while a ring emphasizes a central anchor. These are layout choices your code computes. Compare them by the silhouette visible from the game camera, their width and depth, how they behave on turns, and whether the available terrain can accommodate them.

Layout Typical use Trade-off to consider
Row A clear front line or side-by-side group Can become wide and difficult to fit through narrow routes
Grid A compact group with rows and columns Rear members may be obscured from some camera angles
Wedge A forward-facing silhouette Members occupy different depths and may route around obstacles differently
Column A narrow footprint for constrained spaces The group extends behind the leader and can stretch during turns
Ring A group arranged around an anchor May need explicit rules for the center and for changing membership

No one layout guarantees that the group will retain its ideal shape while moving. Each agent follows its own path and avoidance rules, so actual positions can diverge from the target slots around obstacles.

Define a formation frame and stable slots

Use a leader or another anchor transform as the formation frame. For each member, calculate a local-space offset from its index and the formation settings, then transform that offset into world space. Keep the mapping deterministic so a member does not jump between places merely because the calculation ran again.

This example creates a centered grid in the anchor’s local X-Z plane. It assumes the units have already been assigned stable indices from zero to count - 1; handle joins, removals, and reordering explicitly if those can happen during play.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
using UnityEngine;

public static class FormationLayout
{
    public static Vector3 GridSlotWorld(
        Transform anchor, int index, int count,
        int columns, float spacingX, float spacingZ)
    {
        if (anchor == null) throw new System.ArgumentNullException(nameof(anchor));
        if (count <= 0) throw new System.ArgumentOutOfRangeException(nameof(count));
        if (index < 0 || index >= count)
            throw new System.ArgumentOutOfRangeException(nameof(index));
        if (columns <= 0) throw new System.ArgumentOutOfRangeException(nameof(columns));

        int rows = (count + columns - 1) / columns;
        int column = index % columns;
        int row = index / columns;

        float x = (column - (columns - 1) * 0.5f) * spacingX;
        float z = -row * spacingZ;
        float depthCenter = (rows - 1) * spacingZ * 0.5f;
        Vector3 localOffset = new Vector3(x, 0f, z + depthCenter);

        return anchor.TransformPoint(localOffset);
    }
}

The grid’s columns are centered around the anchor, and its rows extend along local negative Z. This is one convention, not a Unity requirement; change the sign or anchor orientation if your game uses a different forward axis. For a partial last row, the code centers each row according to the full column count, so that final row may not be centered. If that matters visually, calculate each row’s actual member count and center it separately.

Changing the shape

Keep the same interface—member index, group size, spacing and anchor—and replace only the local-offset calculation. For example, a row can use a centered X offset and zero depth. A ring can distribute angles using 2 * Mathf.PI * index / count, then calculate X and Z from the cosine and sine of that angle and a chosen radius. Handle a one-member group separately if a layout formula would otherwise divide by zero.

Give each agent its own destination

Keep slot generation separate from locomotion. The formation code answers where a particular member should stand; a movement component decides how its agent gets there. Unity’s SetDestination requests path calculation, and the resulting path may not be available immediately. Check pathPending rather than treating the request as an instantly completed route. The SetDestination scripting reference documents the request.

using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(NavMeshAgent))]
public sealed class FormationMember : MonoBehaviour
{
    [SerializeField] private NavMeshAgent agent;
    private Vector3 lastRequestedTarget;
    private bool hasRequestedTarget;

    private void Awake()
    {
        if (agent == null)
            agent = GetComponent<NavMeshAgent>();
    }

    public bool RequestSlot(Vector3 worldTarget, float minimumChange = 0.1f)
    {
        if (agent == null || !agent.isOnNavMesh)
            return false;

        if (hasRequestedTarget &&
            (worldTarget - lastRequestedTarget).sqrMagnitude < minimumChange * minimumChange)
            return true;

        if (!agent.SetDestination(worldTarget))
            return false;

        lastRequestedTarget = worldTarget;
        hasRequestedTarget = true;
        return true;
    }

    public bool IsCalculatingPath => agent != null && agent.pathPending;

    public NavMeshPathStatus CurrentPathStatus =>
        agent != null ? agent.pathStatus : NavMeshPathStatus.PathInvalid;
}

Call RequestSlot with the result of the layout function for that member, not with the leader’s position. The small movement threshold is an example policy to avoid repeatedly requesting nearly identical targets; choose a threshold and update cadence appropriate to the project. A moving anchor does not require a new request every frame. Recalculate when the anchor’s position or heading has changed enough to matter, and account for paths that are still pending.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Check whether a slot is reachable

A geometrically valid point is not necessarily a usable destination. Confirm the agent is on a NavMesh and inspect path state after requesting a destination. If a slot cannot be reached, decide how the game should respond: retain the last valid slot, search for a nearby reachable point, or allow that member to temporarily leave formation. These are design decisions, not formation-specific behavior supplied by Unity.

Area masks and navigation settings affect which routes an agent can use. The NavMesh Agent component reference describes properties including radius, height, avoidance, and area masks. A closely spaced pattern may not look as intended when its slots conflict with configured agent radii or avoidance behavior.

Keep the formation readable while it moves

Even correct targets do not guarantee that units maintain a rigid shape in motion. Agents can take different routes and avoid one another, particularly around obstacles. Decide what the player should see: preserve spacing when possible, compress the formation in tight areas, or accept temporary separation while members navigate individually.

Choose how the formation turns

  • Rotate with the leader: Slots respond immediately to the anchor’s heading. This is responsive, but a sharp turn can make targets move across the group.
  • Ease toward the new heading: Rotate the formation frame gradually. This softens sudden target changes but makes the shape trail the leader briefly.
  • Relax constraints during a turn: Let agents move toward a broad destination or retain more of their current positions, then reform. This can reduce abrupt rearrangement at the cost of a temporarily less precise silhouette.

These are formation behavior choices to implement in project code, not built-in Unity modes. Use gizmos to draw intended slots and lines from each unit to its target; that makes it easier to distinguish a layout error from a pathfinding or avoidance effect.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Make movement ownership explicit

For destination-driven movement, let NavMeshAgent own path following and avoidance. Writing directly to NavMeshAgent.velocity changes that arrangement: Unity states that setting velocity overrides movement toward the destination, collision avoidance, and acceleration control, while the agent remains constrained to the NavMesh. In Unity 6.0, the velocity scripting reference says: “Setting the variable will override the simulation (including: moving towards destination, collision avoidance, and acceleration control) and command the NavMesh Agent to move using the specific velocity directly.”

If custom steering writes velocity, treat that as the movement controller rather than assuming destination following still applies. Likewise, if root motion or another component moves the transform, define which system owns position changes and how the others receive movement information. Unity warns that competing movement controllers can produce undefined behavior or feedback problems in its guidance on mixing navigation components.

Validate the layout in a small scene

Set up a simple scene with a baked NavMesh, a leader marker, several units with agents, and visible slot gizmos. This is a practical validation approach, not a claim of measured performance. Check the layout while stationary, as the leader moves, during a turn, and with an obstacle between some units and their targets.

  • Verify that every member receives a distinct, stable slot.
  • Check that slots lie on areas the agent can traverse, and watch for invalid or partial paths.
  • Compare the visual gap between units with their agent radii and avoidance settings.
  • Watch whether repeated target updates create needless path requests or visible jitter.
  • Confirm only the intended controller moves each agent or transform.

Editor workflows and AI Navigation package details can vary by Unity version. Match the setup and API references to the Unity version and package used by your project; the API examples here use Unity’s documented NavMeshAgent destination and velocity behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.