§ How to · with Picoo
How to make a gun in Roblox Studio
By Sametcan Tasgiran, Founder & Developer·Published ·Updated
A gun is where client trust becomes free kills: if the client reports the hit, the client decides who dies.
The Tool, the Handle configuration, and the damage validation are three separate things people get wrong — usually in that order.
Equippable Tool
A Flamethrower Tool in StarterPack whose Handle is an unanchored Part styled as a dark metal barrel. At Play, a script welds a glowing muzzle, a fuel tank and a grip onto it.
Server-authoritative damage
The client sends where it fired from and which way it aimed. The server works out who was hit and applies the damage.
Rate limit + origin check
The server drops a shot if the player is not holding the weapon, fires more often than the rate limit allows, or claims an origin more than 18 studs from their HumanoidRootPart.
Range and cone
Cone mode, the default, hits every Humanoid within 45 studs and within 35° of the aim for 12 damage, up to ten times a second while the trigger is held.
Fire burst for everyone
Each accepted shot spawns a fire particle burst from the server, so every player sees the spray.
Reskinnable
Bolt mode fires a travelling neon projectile instead (a Blaster by default: 35 damage, 250-stud range). Name, damage, range, cone angle, fire rate, bolt speed and colours are all settings you can ask for in the prompt.
Files Picoo ships for this prompt
5 files · 144 lines · one recipe call
ServerScriptService.FlamethrowerServer
The authority: checks the tool, fire rate and origin, spawns the fire burst, and damages every Humanoid in the cone.
71 lines
StarterPack.Flamethrower.FlamethrowerLocal
While the trigger is held, sends the Handle position and the aim toward the mouse every 0.1 seconds.
34 lines
StarterPack.Flamethrower.FlamethrowerCosmetic
At Play, welds a neon muzzle, a fuel tank and a grip onto the Handle so it does not look like a grey brick.
39 lines
StarterPack.Flamethrower (Tool + Handle)
The Tool and its Handle Part, sized and coloured as a metal barrel in Edit mode.
instance
ReplicatedStorage.Remotes.FlamethrowerFire
RemoteEvent the client fires with its origin and aim direction.
instance
Sample output: ServerScriptService.FlamethrowerServer
FireEvent.OnServerEvent:Connect(function(player: Player, origin: Vector3, direction: Vector3)
local character = player.Character
if not character then return end
local humanoid = character:FindFirstChildOfClass("Humanoid")
if not humanoid or humanoid.Health <= 0 then return end
local tool = character:FindFirstChildOfClass("Tool")
if not tool or tool.Name ~= WEAPON_NAME then return end
if typeof(origin) ~= "Vector3" or typeof(direction) ~= "Vector3" then return end
local now = tick()
if lastFire[player.UserId] and (now - lastFire[player.UserId]) < TICK_RATE * 0.7 then return end
lastFire[player.UserId] = now
local root = character:FindFirstChild("HumanoidRootPart") :: BasePart?
if not root or (origin - root.Position).Magnitude > 18 then return end
local dir = direction.Unit
spawnConeVFX(origin, dir)
for _, hum in ipairs(workspace:GetDescendants()) do
if hum:IsA("Humanoid") and hum ~= humanoid and hum.Health > 0 then
local hRoot = hum.Parent and hum.Parent:FindFirstChild("HumanoidRootPart") :: BasePart?
if hRoot then
local toTarget = hRoot.Position - origin
local dist = toTarget.Magnitude
if dist > 0 and dist <= RANGE and dir:Dot(toTarget.Unit) >= COS_LIMIT then
hum:TakeDamage(DAMAGE)
end
end
end
end
end)Building a gun in Roblox Studio
Guns fail in three distinct places, and most tutorials only cover the first one.
The first is the Tool itself. A Roblox Tool needs a BasePart child named exactly "Handle", and that part has to be unanchored. Leave it anchored and the weapon equips while the model stays hanging in the air where you built it. None of this errors; it just looks broken.
The second is who decides what got hit. The convenient design is for the client to raycast and tell the server "I hit this player", and it is the reason so many Roblox shooters are trivially exploitable. That code runs on the player's machine, so the message can say anything: everyone, at once, for any damage. The fix is a boundary, not a check: the client sends where it fired from and which way it aimed, the server confirms that origin is next to the player's character, and the server works out the hit. The client can still aim anywhere; it cannot report a hit.
The third is rate. Without a server-side fire-rate timestamp, a modified client fires every frame. Same shape as a cooldown, same reason it has to live on the server.
Picoo's projectile_weapon recipe is built on those three rules. Ask for a flamethrower, a blaster, a laser gun or "a gun that shoots" and it puts the Tool and its Handle in StarterPack, a server Script in ServerScriptService and a RemoteEvent in ReplicatedStorage.Remotes. The default Flamethrower checks the tool, the fire rate and an origin within 18 studs of the player, then damages every Humanoid within 45 studs and 35° of the aim. Bolt mode fires a travelling projectile instead. Both spawn their effects on the server, so every player sees the same shot.
See more on the Luau generator, the AI Luau script writer, the 3D model generator and the game builder, read how Picoo compares with ChatGPT, or browse the full blog.
Frequently asked
Why does my Roblox gun not appear in the player's hand?+
The Handle. A Tool needs a BasePart child named exactly "Handle", and it must be unanchored. An anchored Handle is the classic one: the Tool equips and the model stays floating where you built it. Setting CanCollide false and Massless on the Handle also keeps it from bumping into things and dragging on the character.
Should the client or the server detect hits?+
The server. If the client reports what it hit, an exploiter reports hitting everyone at once from across the map, and no amount of client-side validation stops it, because that code runs on their machine. Send the aim, let the server work out the hit.
Does server-side hit detection make shooting feel laggy?+
Damage lands one network round trip after the trigger is pulled. In this recipe the fire burst is also spawned by the server, so the shooter sees it after that same round trip. For an instant effect on the shooter's own screen, ask for a local muzzle flash in a follow-up prompt; the damage stays on the server either way.
How do I stop rapid-fire exploits?+
Keep the fire rate on the server with a per-player timestamp, exactly like a cooldown. A client-side debounce is a UI convenience; the server's is the rule. Validate the origin too: this recipe drops any shot whose origin is more than 18 studs from the player's HumanoidRootPart, so a spoofed origin cannot fire from across the map.
Can I make it a laser or a water gun instead?+
Yes. Ask for a laser gun, a blaster or a water gun. Bolt mode, a travelling projectile that damages the first Humanoid it touches, suits a laser or blaster; cone mode in a new colour suits a water gun. You can set damage, range, fire rate and colours in the same prompt.
Related Picoo prompts
Roblox combat system
3 scripts · 1,181 lines · one recipe call. Press Play and fight with M1, E, F, Q, R and Shift.
an ability system with cooldowns in Roblox
If the cooldown lives on the client, it is a suggestion. Every cooldown, cost and damage number here is enforced on the server.
How to prevent exploits in Roblox
Example output: 4 files · 160 lines of guards. The model writes this code for your game, so the files and line counts vary.