Gessa Docs
Recipes

Recipe

Turrets auto-aim and target tracking guns

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.
engine v1.0.234since script-semantic-patch-ops.v1, action-catalog.v1.0.232, world.v1, physics.v1, timer.v1, spawn.v1, mutation.v1Copy for LLM

Use this for

a stationary turret or sentry that finds a target and fires on its own; a tower or cannon that rotates to track the nearest enemy; auto-aiming mounted guns; lock-on tracking

Not for

a player-aimed weapon fired by input (see projectiles-and-ranged-weapons); a moving enemy that walks and chases (see npc-enemy-navigation); melee contact damage (see combat-damage-and-respawn)

Pairs with: Projectiles bullets and ranged weapons, NPC and enemy navigation chase and patrol behavior, Timers countdowns cooldowns and enemy waves, Combat damage health and respawn scripting

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.
Was this helpful?Report an issueContact support

On this page