Tutorial · 11 min read · Updated October 2026
How to make a Roblox tower defense game with AI, step by step
Tower defense looks simple and is not: a path, waves, placement, targeting, upgrades and an economy all have to agree with each other, and every one of them is an exploit if the client is in charge. This guide is the message sequence that builds a working TD game inside your own Roblox Studio place, one system at a time, with a playtest after each. The prompts are written for ForgeBlox but work with any agent that can act in Studio.
Before you start
- Roblox Studio open on a new Baseplate, saved once.
- Studio ▸ Assistant ▸ ⋯ ▸ Manage MCP Servers ▸ Enable Studio as MCP server.
- The ForgeBlox Bridge running and paired on your Windows PC.
- One rule for the whole build: ask for one system per message. "Build me a tower defense game" in one prompt produces systems that do not fit together.
Message 1: the map and the path
Build a tower defense map in Workspace/Map: a 200x200 grass base, a winding
dirt path with 8 turns from an EnemySpawn to a Base at the other end. Put
invisible, anchored, non-collidable waypoint parts named 1, 2, 3... in
Workspace/Map/Waypoints at the path start, every corner, and the Base. Add
grey PlacementZone parts along both sides of the path where towers may go.
The Base has a Health attribute of 100 shown on a BillboardGui. Screenshot
from above.
Numbered waypoints are the backbone of the whole game. Enemies walk them in order, and the waypoint index doubles as "how far along the path" an enemy is, which towers use for targeting later.
Message 2: enemies and waves
Add enemies. Templates in ServerStorage/Enemies: Normal (100 HP, speed 10),
Fast (60 HP, speed 18), Tank (400 HP, speed 6). A server module walks each
enemy through Map/Waypoints in numeric order, sets a Progress attribute to the
current waypoint index, sets network owner to the server, and on reaching the
Base subtracts its damage from Base Health and despawns. A WaveManager reads
waves from ReplicatedStorage/Config/Waves (10 waves, increasing counts and
mixes), waits for the wave to clear, then starts a 10s intermission. Add a
Cash leaderstat; kills reward cash on the server. Playtest wave 1-2,
screenshot, read the console.
The movement core should look roughly like this. Note the retry loop: Humanoid:MoveTo gives up after about eight seconds, so without it, enemies stall on long straights.
local function walk(enemy: Model, waypoints: {BasePart})
local humanoid = enemy:FindFirstChildOfClass("Humanoid")
local root = enemy:FindFirstChild("HumanoidRootPart") :: BasePart
root:SetNetworkOwner(nil) -- server owns movement: no jitter, no client teleporting
for index, waypoint in waypoints do
enemy:SetAttribute("Progress", index)
local reached = false
repeat
if humanoid.Health <= 0 or not enemy.Parent then return false end
humanoid:MoveTo(waypoint.Position)
reached = humanoid.MoveToFinished:Wait()
until reached
end
return true -- reached the base
end
local function sortedWaypoints(folder: Folder): {BasePart}
local list = folder:GetChildren()
table.sort(list, function(a, b) return tonumber(a.Name) < tonumber(b.Name) end)
return list
end
Message 3: tower placement
Add tower placement. ReplicatedStorage/Config/Towers: Archer (cost 100,
range 18, damage 15, fire rate 1/s), Cannon (cost 250, range 14, damage 50
splash 6, 0.4/s), Frost (cost 200, range 16, slows 40% for 2s). Client: a
tower bar on the HUD, a ghost preview that follows the mouse or touch and turns
red where placement is invalid. Server: a PlaceTower RemoteEvent that checks
the tower name exists, the player has the cash, the position is on a
PlacementZone, not on the path, and at least 4 studs from other towers, then
deducts cash and spawns the tower. Playtest, place two towers, screenshot.
The preview is cosmetic; the server check is the real rule. If the agent ever deducts cash on the client, send "move all cost checks and deductions to the server".
Message 4: targeting and damage
Add a single server loop that runs every 0.1s and, for each tower whose
cooldown is ready, picks the living enemy within range with the highest
Progress (first in line), applies damage on the server, and fires a
lightweight effect to clients (beam or projectile, client-only visuals).
Cannon applies splash, Frost applies the slow. Playtest waves 1-3 with three
towers placed, screenshot, read the console.
One loop for all towers is much cheaper than one script per tower, and "highest Progress in range" is the classic "first" targeting players expect:
local function findTarget(origin: Vector3, range: number): Model?
local best, bestProgress = nil, -1
for _, enemy in workspace.Enemies:GetChildren() do
local root = enemy:FindFirstChild("HumanoidRootPart")
local humanoid = enemy:FindFirstChildOfClass("Humanoid")
if root and humanoid and humanoid.Health > 0
and (root.Position - origin).Magnitude <= range then
local progress = enemy:GetAttribute("Progress") or 0
if progress > bestProgress then
best, bestProgress = enemy, progress
end
end
end
return best
end
Message 5: upgrades and selling
Clicking a placed tower opens a small panel: two upgrade levels per tower
(+range and +damage, prices in the Towers config) and Sell for 60% of total
spent. UpgradeTower and SellTower RemoteEvents verify the player owns that
tower, the level exists and they can afford it. Show range as a circle while
the panel is open. Playtest, upgrade and sell one tower, screenshot.
Message 6: saving and the HUD
Save per player with DataStoreService (pcall, UpdateAsync, autosave every 60s,
save on leave and in BindToClose): unlocked towers and best wave reached.
In-match cash is not saved. HUD: wave number, Base health bar, cash, tower bar
with costs, a Start Wave / Skip Intermission button. All scale-based,
ScreenInsets DeviceSafeInsets. Check the iPhone preset in the device emulator
and screenshot.
For the HUD and tower bar to look like your game rather than a default, attach screenshots or mockups of the look you want, or see the Roblox UI guide.
Message 7: performance and security pass
Spawn a stress wave of 150 Normal enemies and report the server frame rate
and script activity. If it drops, reduce per-enemy work (no per-enemy loops,
no per-frame FindFirstChild). Then review every RemoteEvent and RemoteFunction:
validate types and ranges, rate-limit per player, never trust client-sent
positions without re-checking, never trust client-sent prices. Fix and
summarise.
Humanoid enemies are convenient but heavy. If the stress test struggles, ask the agent to switch enemies to anchored models moved along the waypoints by one server loop with CFrame interpolation; it scales much further and is a common pattern in large TD games.
What it costs
On Sonnet 5.5 a build step typically costs 20–150 credits ($0.20–$1.50). This sequence is about the same size as the tycoon guide, which runs roughly 2,500–6,000 credits depending on how many fixes the playtests catch. Every message shows its price before you send it, and credit packs start at $10 on the pricing page.
Before you publish
- Play all 10 waves yourself. Balance is the part no AI can feel for you: if wave 6 is impossible without a specific tower, players quit.
- Playtest with two clients (Test ▸ Clients and Servers) to check placement and cash are per player.
- If you sell towers or skips, set up passes and products with the game pass guide.
- Set the genre, write a description with "tower defense" in the first sentence, and publish private first.
Questions
Can AI make a Roblox tower defense game?
An agent working inside Studio can build the path, enemies, waves, placement, targeting, upgrades, saving and UI, and playtest each step. You still decide the balance, the art direction and what makes your game different.
Why do my tower defense enemies stop walking?
Humanoid:MoveTo gives up after about eight seconds if the target is not reached. Place waypoints closer together, or call MoveTo again until MoveToFinished reports the waypoint was reached, as in the snippet above.
Should towers attack on the client or the server?
Damage and targeting run on the server. The client can play the shot effect, but if the client decides damage, exploiters can clear every wave instantly.
How many enemies can a Roblox tower defense handle?
It depends on your models and scripts. Humanoid enemies are the heaviest option; anchored parts moved by one server loop scale much further. Load-test your biggest wave in Studio before publishing.
Related guides
- How to make a Roblox tycoon with AI
- How to make a Roblox simulator with AI
- Roblox AI script generators: what to use and how to check the Luau
- Roblox AI tools compared
- How to make a Roblox RPG with AI: enemies, XP and a boss fight.