§ How to · with Picoo

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

By Sametcan Tasgiran, Founder & Developer·Published ·Updated

A Roblox sword-fighting game lives or dies on game-feel: a snappy M1 combo, a heavy finisher, a block, a parry window that rewards timing, and a dash with invincibility frames. Picoo's combat_system recipe generates every one of these — server-authoritative and exploit-safe — from a single prompt.

One CombatSystem folder · hitbox module + server + client · server-authoritative · 1 recipe call.

M1 combo chain

The client counts the combo (resets after ~0.8s of no input) and fires intent only; the server owns damage. The 4th hit is a knockback finisher.

Heavy attack (stamina-gated)

E triggers a heavy that deals extra damage plus knockback and costs stamina, so it can't be spammed.

Block + 75% damage reduction

Hold F to block. The server caps how long you can hold it — killing infinite-block — and reduces incoming damage by 75%.

Parry window → attacker stun

Tap Q for a short parry window. A hit landing inside it deals zero damage and STUNS the attacker — the skill-expression core of every good sword game.

Dash with i-frames

Shift dashes with a client LinearVelocity burst; the server grants invincibility frames plus a cooldown, so it reads as a real dodge, not a teleport.

Server hitbox (never .Touched)

Hit detection uses workspace:GetPartBoundsInBox in front of the attacker with an OverlapParams filter — never .Touched, which misses fast swings.

Files Picoo ships for this prompt

4 files · 214 lines · under a minute · 5 credit

ServerScriptService/CombatSystem/HitboxModule.lua

GetPartBoundsInBox hitbox with self-filter — returns enemy Humanoids

34 lines

ServerScriptService/CombatSystem/CombatServer.lua

Owns all state: combo, stamina, block, parry, stun, damage

120 lines

StarterPlayerScripts/CombatClient.lua

Binds M1/E/F/Q/Shift, tracks combo, sends intent, client dash

60 lines

ReplicatedStorage/CombatRemotes/CombatAction

One RemoteEvent — action name + combo index only

instance

Sample output: ServerScriptService/CombatSystem/HitboxModule.lua

--!strict
-- ServerScriptService/CombatSystem/HitboxModule.lua  (Picoo)
-- Box hitbox in FRONT of the attacker. Never .Touched (misses fast swings).
local Hitbox = {}

function Hitbox.hit(attacker: Model, size: Vector3, reach: number): { Humanoid }
	local root = attacker:FindFirstChild("HumanoidRootPart") :: BasePart?
	if not root then return {} end
	local params = OverlapParams.new()
	params.FilterType = Enum.RaycastFilterType.Exclude
	params.FilterDescendantsInstances = { attacker }
	local cf = root.CFrame * CFrame.new(0, 0, -reach)
	local hits: { Humanoid } = {}
	for _, part in ipairs(workspace:GetPartBoundsInBox(cf, size, params)) do
		local hum = part.Parent and part.Parent:FindFirstChildOfClass("Humanoid")
		if hum and hum.Health > 0 and not table.find(hits, hum) then
			table.insert(hits, hum)
		end
	end
	return hits
end

return Hitbox

Building a Roblox sword fighting game

Sword-fighting is one of the highest-retention genres on Roblox — Blade Ball and countless anime combat games all run on the same core loop: a light-attack combo, a heavy, a block, a parry, and a dash. What separates a game that feels good from one that feels broken lives entirely in the details: does the combo reset at the right time, does the parry window reward timing, does the dash actually dodge, and — critically — is any of it exploitable.

The single most common way sword games get destroyed is client-trusted damage. If the client sends "I hit for 30", an exploiter sends "I hit for 9999" and one-shots the server. Picoo's combat_system recipe is built server-first: the client fires only an intent (the action name and the current combo index), and the server owns every damage calculation, cooldown, stamina check, and hitbox query. There is no code path where a client number becomes a damage number.

Hit detection uses workspace:GetPartBoundsInBox — a box query projected in front of the attacker's HumanoidRootPart, filtered to exclude the attacker's own character via OverlapParams. This is deliberately not .Touched, which misses fast swings and misfires under load, and not the deprecated RaycastHitbox module. The box query is deterministic: every swing checks exactly the volume in front of the blade.

The skill layer is block and parry. Block (hold F) reduces incoming damage by 75%, but the server enforces a maximum hold time so nobody turtles forever. Parry (tap Q) opens a short window; a hit landing inside it deals zero damage and stuns the attacker — the timing-reward loop that every competitive sword game is built around. Dash (Shift) applies a client-side LinearVelocity burst for responsiveness while the server grants invincibility frames and a cooldown, so it reads as a real dodge instead of a teleport.

To ship a full sword-fighting game, pair combat_system with the sword_tool recipe: sword_tool gives you an equipping, glowing weapon (pass element: 'fire' for a flaming blade with a swing trail), and combat_system gives you the mechanics that make swinging it feel good. Both are deterministic recipes, so you get the same working result every time instead of the run-to-run variance of hand-prompted combat code.

See more on the Luau generator, the game builder, or browse the full blog.

Frequently asked

How is the combo exploit-proof?+

The client only sends the action name and combo index — never a damage number. The server holds the combo state, validates cooldown and stamina, runs the hitbox itself, and applies damage. An exploiter can spam the RemoteEvent; the server still rejects out-of-cooldown or out-of-range hits.

Why not use .Touched for hit detection?+

.Touched misses fast weapon swings and fires unreliably under server load. Picoo uses workspace:GetPartBoundsInBox with an OverlapParams filter — a deterministic box query in front of the attacker that catches every swing. It is also not the deprecated RaycastHitbox module.

Does the parry actually stun the attacker?+

Yes. When a hit lands inside a target's parry window, the server deals zero damage and applies a stun to the attacker (WalkSpeed and JumpPower zeroed for a short duration). That timing-reward loop is what makes a sword game feel skillful.

Can I retexture the sword to glow or flame?+

Yes — pair combat_system with the sword_tool recipe and pass element: 'fire' (or ice/void/lightning). You get a Neon blade, a PointLight aura, element particles, and a swing trail on top of the combat mechanics.

How many credits does it cost?+

The combat_system recipe is a single deterministic composition — around 5 credits — versus dozens of credits and many failed attempts hand-prompting a combo, parry, and dash system from scratch.

Related Picoo prompts