§ How to · with Picoo

How to make a Roblox sword fighting game (with AI)

By Sametcan Tasgiran, Founder & Developer·Published ·Updated

Every Roblox sword fighting game starts with the sword: a Tool that sits in the hand, a swing that plays an animation, and damage the server decides. Ask Picoo for a sword fighting game and it applies its sword_tool recipe: a Sword in StarterPack, so every player spawns with one, with every hit checked on the server.

5 files · 139 lines · one recipe call. Set damage, reach and cooldown, or ask for a glowing element blade, in the prompt; combos, blocking and parry are a follow-up prompt.

Sword Tool in StarterPack

A Tool named Sword with a Handle, so every player spawns with one in their Backpack. The Handle does not collide and is massless, and RequiresHandle and GripPos are set, so the sword sits in the hand when equipped.

Server-side hit check

The client sends only the swing. The server checks that the player is holding the Sword, enforces a 0.5-second cooldown with its own clock, and picks the target itself: the closest living Humanoid whose HumanoidRootPart is within 8 studs.

Damage for players and NPCs

The target takes 25 damage through Humanoid:TakeDamage. Any Humanoid counts, so the same sword works in PvP and against NPCs. A player can hit the same player at most once every 0.4 seconds.

Roblox slash animation

The server adds a toolanim value that makes the default Animate script play Roblox's own slash on R6 and R15 rigs, visible to every player. If the game has removed Animate, the LocalScript plays the matching slash itself.

Hit sound and sparks

Each hit plays swordslash.wav and bursts 30 spark particles at the target, both cleaned up with Debris.

Element blades

Ask for a fire, ice, void, lightning, shadow or holy sword and the blade turns Neon in that color. The LocalScript adds a PointLight, a stream of element particles and a trail that shows during each swing, drawn on the holder's client.

Files Picoo ships for this prompt

5 files · 139 lines · one recipe call

StarterPack/Sword

The Tool. RequiresHandle is on, CanBeDropped is off, and GripPos seats the hilt in the hand.

instance

StarterPack/Sword/Handle

The blade: a 0.3 × 0.3 × 5.5 stud Metal Part with CanCollide off and Massless on, so it welds to the hand when equipped.

instance

StarterPack/Sword/SwordLocal.lua

LocalScript: on click, fires the swing to the server and plays the slash itself if the character has no Animate script.

37 lines

ServerScriptService/SwordServer.lua

Server Script: checks the swing, finds the closest Humanoid in reach, applies the damage, and plays the hit sound and sparks.

102 lines

ReplicatedStorage/Remotes/SwordSwing

RemoteEvent the client fires on each swing. It carries no target and no damage.

instance

Sample output: ServerScriptService/SwordServer.lua

--!strict
-- Generated by Picoo recipe: sword_tool
-- Server-authoritative damage: validates player holds Tool, target in range, debounce
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")

local DAMAGE = 25
local ATTACK_RANGE = 8
local COOLDOWN = 0.5
local HIT_DEBOUNCE = 0.4

local Remotes = ReplicatedStorage:WaitForChild("Remotes")
local SwordSwing: RemoteEvent = Remotes:WaitForChild("SwordSwing") :: RemoteEvent

local lastSwing: { [number]: number } = {}
local lastHit: { [string]: number } = {}

local function findHumanoidInRange(player: Player): Humanoid?
	local character = player.Character
	local rootPart = character and character:FindFirstChild("HumanoidRootPart") :: BasePart?
	if not rootPart then return nil end
	local closestHumanoid: Humanoid? = nil
	local closestDist = ATTACK_RANGE
	for _, other in ipairs(workspace:GetDescendants()) do
		if other:IsA("Humanoid") and other.Parent ~= character and other.Health > 0 then
			local otherRoot = other.Parent:FindFirstChild("HumanoidRootPart") :: BasePart?
			if otherRoot then
				local d = (otherRoot.Position - rootPart.Position).Magnitude
				if d <= closestDist then closestDist = d; closestHumanoid = other end
			end
		end
	end
	return closestHumanoid
end

SwordSwing.OnServerEvent:Connect(function(player: Player)
	local character = player.Character
	if not character then return end
	local tool = character:FindFirstChildOfClass("Tool")
	if not tool or tool.Name ~= "Sword" then return end

	local now = tick()
	if lastSwing[player.UserId] and (now - lastSwing[player.UserId]) < COOLDOWN then return end
	lastSwing[player.UserId] = now

	-- (excerpt) the Roblox slash animation is triggered here, then:

	local target = findHumanoidInRange(player)
	if not target then return end

	local targetPlayer = Players:GetPlayerFromCharacter(target.Parent)
	if targetPlayer then
		local pairKey = player.UserId .. ":" .. targetPlayer.UserId
		if lastHit[pairKey] and (now - lastHit[pairKey]) < HIT_DEBOUNCE then return end
		lastHit[pairKey] = now
	end

	target:TakeDamage(DAMAGE)
	-- (excerpt ends) then the hit sound and a 30-spark burst at the target

Building a Roblox sword fighting game

Sword fighting games live or die on the sword, and the sword is where hand-written code usually breaks. A Tool whose Handle collides will not weld to the hand, and a swing that trusts the client lets an exploiter hit anyone from anywhere. Picoo builds the sword from a fixed recipe, sword_tool, so both are handled the same way every time.

The Tool goes in StarterPack, so every player spawns with it. Its Handle is a 0.3 × 0.3 × 5.5 stud Metal blade with CanCollide off, Anchored off and Massless on, and the Tool has RequiresHandle on and a GripPos that seats the hilt in the hand. These are set as properties when the sword is created, before anyone equips it.

When a player clicks, the LocalScript checks its own 0.5-second cooldown and fires SwordSwing with no arguments. Everything that matters happens on the server: it confirms the player is holding the Sword, applies the same cooldown with its own clock, and searches the workspace for the closest living Humanoid whose HumanoidRootPart is within 8 studs. That Humanoid takes 25 damage, a slash sound plays, and 30 sparks burst from the target. A player can hit the same player at most once every 0.4 seconds.

The swing animation is Roblox's own Slash. The server adds a toolanim value to the Tool, which the default Animate script plays on R6 and R15 rigs; if your game has replaced Animate, the LocalScript plays the matching slash itself. Name an element (fire, ice, void, lightning, shadow or holy) and the blade turns Neon in that color, and the LocalScript adds a light, element particles and a swing trail on the holder's client.

That is the weapon. A sword fighting game adds rules around it, and each of those is a follow-up prompt: an arena, rounds with a winner, a kill leaderboard, or a combat layer with combos, blocking and parry.

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

What does Picoo build when I ask for a sword fighting game?+

Its sword_tool recipe: a Sword Tool in StarterPack with its Handle and a LocalScript, a server Script, and a SwordSwing RemoteEvent. Every player spawns with the sword, so players can fight as soon as the game starts. An arena, rounds, a kill counter or a leaderboard are follow-up prompts.

Can an exploiter fake a hit or the damage?+

The client never sends a target or a damage number; SwordSwing carries only the swing. The server checks that the player holds the Sword and that 0.5 seconds have passed since their last swing, then picks the closest living Humanoid within 8 studs of the player's HumanoidRootPart and applies the damage set on the server.

Can I change damage, reach and speed, or add more swords?+

Yes. Describe the sword and Picoo passes the values to the recipe: name, damage (default 25), attack_range (8 studs), cooldown (0.5 seconds), handle color, element and swing style. 'A fire katana that does 40 damage' covers name, element and damage. A sword with a different name gets its own Tool, scripts and RemoteEvent, so several swords can sit in StarterPack side by side.

How do I add combos, blocking and parry?+

Ask for them in a follow-up prompt. This recipe gives you the sword and a single swing; a combo chain, a heavy attack, blocking, a parry window and stamina are a combat layer built on top of it.

What about animations?+

The swing uses Roblox's own Slash animation. The server adds a toolanim value to the Tool, which the default Animate script plays on R6 and R15 rigs for every player to see; if your game has removed Animate, the LocalScript plays the matching slash itself. Ask for a procedural swing and the recipe instead arcs the blade through Tool.Grip and swings the right arm in code, with no animation asset.

Related Picoo prompts