---
title: "Turrets auto-aim and target tracking guns"
description: "A fixed gun watches an area, swivels to the closest enemy, and fires without a player pulling the trigger. There is no TurretComponent; a turret is a find-rotate-fire loop composed from world queries, a Transform patch, and the projectile recipe."
engineVersion: v1.0.234
date: 2026-09-28
license: "(c) Gessa, proprietary. Cite with attribution to https://gessa.ai/docs/. Terms: https://gessa.ai/terms/."
canonical: https://gessa.ai/docs/knowledge/playbooks/turrets-and-auto-aim/
---

# Turrets auto-aim and target tracking guns

## When to use

A fixed gun watches an area, swivels to the closest enemy, and fires without a
player pulling the trigger. There is no TurretComponent; a turret is a
find-rotate-fire loop composed from world queries, a Transform patch, and the
projectile recipe.

## The recipe

Author with `project_apply_script_semantic_patch` using the `ai_safe` op pack.

1. Acquire a target each think: `addTickHandler` `{ "handlerKey":"onTrack" }`,
   and inside a GessaScript body (`replaceScriptFromGessaScript`) call
   `ctx.world.find` with a tag and a radius (or `findEntitiesByTag`) to list
   candidates, then pick the nearest by comparing positions.
2. Face the target: compute the aim direction to the chosen target and
   `ctx.entity.patchComponent` the turret barrel `TransformComponent` `rotation`
   to point at it. Parent the barrel under a base pivot with `ctx.entity.setParent`
   if only the barrel should swivel.
3. Line of sight (optional): `ctx.physics.shapecast` from the muzzle toward the
   target and only fire if the cast reaches the target and is not blocked.
4. Fire on a cooldown: gate firing with a `TimerComponent` plus `addTimerHandler`
   (or a last-fired timestamp in state with `setBooleanState` a `ready` flag).
   On fire, `spawnEntityFromTemplate` `{ "prefabKey": <projectile> }` at the
   muzzle and launch it with `ctx.physics.command` (see
   projectiles-and-ranged-weapons for the launch and impact damage).
5. Idle when no target: if the query returns nothing, hold or slowly sweep the
   barrel and do not fire.

## Pitfalls

- Recompute the nearest target on a throttled tick, not every frame; unbounded
  per-tick world scans are costly (keep the query radius and limit small).
- Rotate the barrel through `ctx.entity.patchComponent`; never write
  `VelocityComponent` to spin it (it is engine-internal and hidden from authoring).
- Aim uses the target's live position; lead the shot for fast movers by aiming
  ahead, since the projectile takes time to travel.
- The turret fires for all players from the authority; do not run a parallel
  client-side turret or shots will duplicate.

## Verify

- `simulation_run` (`qa.run.start`) to prove the turret acquires the nearest
  target, rotates to face it, and fires on its cooldown.
- `project_get_graph_snapshot` to confirm the tracking tick handler and the fire
  cooldown timer landed.
