GM Market — Premium GMod & FiveM Scripts
Roblox Guide 🇺🇸 English

Roblox Hit Detection Guide: Raycast, RaycastParams & FastCast for Weapons

Mateo
@Mateo ·
8 views 0 replies

TL;DR

Building a solid hit detection system for ranged weapons needs three things: understanding Workspace:Raycast(), configuring RaycastParams to filter the right objects, and knowing when to swap to FastCast for projectiles with gravity and travel time. On top of that, all damage logic must be validated server-side.


1. Workspace:Raycast() — The Hitscan Foundation

When you call Workspace:Raycast(origin, direction, raycastParams), the engine checks along the path of the ray and returns information about the first object it intersects, such as the position of the hit, the normal of the surface, and the part itself.

A minimal hitscan fire function on the LocalScript side:

local Players = game:GetService("Players")
local player  = Players.LocalPlayer
local char    = player.Character or player.CharacterAdded:Wait()
local handle  = script.Parent:WaitForChild("Handle")

local function fireWeapon(targetPosition)
    local origin    = handle.Position
    local direction = (targetPosition - origin).Unit * 500  -- 500 stud range

    local rayParams = RaycastParams.new()
    rayParams.FilterDescendantsInstances = {char}
    rayParams.FilterType = Enum.RaycastFilterType.Exclude
    rayParams.IgnoreWater = true

    local result = workspace:Raycast(origin, direction, rayParams)
    if result then
        script.Parent.HitEvent:FireServer(result.Instance, result.Position)
    end
end

2026 API update: Roblox has added RaycastParams.ExcludeInstances and RaycastParams.IncludeInstances as cleaner replacements for FilterDescendantsInstances. The ExcludeInstances and IncludeInstances properties store a set of objects and their descendants that will be excluded and included from the query. Note that FilterDescendantsInstances has been superseded by ExcludeInstances and IncludeInstances, which should be used for new work.


2. Configuring RaycastParams

Raycast parameters allow you to fine-tune what your raycast detects — for example, you might want to ignore certain objects like transparent parts, or only detect objects tagged as enemies. Using RaycastParams, you can set a collision group to include or exclude specific groups, or ignore the player's own character to avoid self-collision.

PropertyUse
ExcludeInstancesObjects to skip — shooter's character, weapon model
IncludeInstancesWhitelist — only these objects can be hit
IgnoreWaterSkip Terrain water
CollisionGroupRestrict to a physics collision group

FilterType quick reference:

  • Exclude — every BasePart is considered except those that are descendants of objects in the array.
  • Include — only BaseParts that are descendants of objects in the array are considered.

3. FastCast — Projectiles with Gravity

Standard raycasting is instantaneous — great for lasers and hitscan rifles. For arrows, grenades, or any bullet with visible travel time and drop, use FastCast.

FastCast is a module that uses raycasting (commonly used for hitscan weapons, like lasers) in such a way that these raycasts can simulate bullet physics. Each frame it casts a short ray between the projectile's previous and current position, catching collisions accurately even at high speeds.

Get FastCast Redux from the Toolbox (library ID 4453855787).

Setup

local FastCast    = require(game.ReplicatedStorage.FastCastRedux)
local caster      = FastCast.new()

local castParams  = RaycastParams.new()
castParams.FilterDescendantsInstances = {workspace.Bullets}
castParams.FilterType = Enum.RaycastFilterType.Exclude

local castBehavior = FastCast.newBehavior()
castBehavior.Acceleration             = Vector3.new(0, -workspace.Gravity, 0)
castBehavior.CosmeticBulletTemplate   = game.ReplicatedStorage.BulletPart
castBehavior.CosmeticBulletContainer  = workspace.Bullets

local function shootProjectile(origin, direction, speed)
    caster:Fire(origin, direction, speed, castBehavior, castParams)
end

Setting castBehavior.Acceleration to Vector3.new(0, -workspace.Gravity, 0) produces natural bullet drop. Tune it per weapon — an arrow needs more arc than a sniper bullet.

Hit Event

caster.LengthChanged:Connect(function(cast, lastPoint, dir, length, velocity, bullet)
    if bullet then
        bullet.CFrame = CFrame.lookAt(lastPoint + dir * length, lastPoint + dir * (length + 1))
    end
end)

caster.RayHit:Connect(function(cast, result, velocity, bullet)
    game.ReplicatedStorage.HitEvent:FireServer(result.Instance, result.Position, velocity)
    if bullet then bullet:Destroy() end
end)

caster.CastTerminating:Connect(function(cast)
    local b = cast.RayInfo.CosmeticBulletObject
    if b then b:Destroy() end
end)

4. Server-Side Hit Validation

This is the step most tutorials skip — and it's the most important for anti-cheat.

The biggest issue with remote events is that an exploiter can fire them from the client and alter the value sent to be something it shouldn't. Always validate on the server before applying damage.

-- ServerScript
local MAX_RANGE  = 500
local MAX_DAMAGE = 50

game.ReplicatedStorage.HitEvent.OnServerEvent:Connect(function(shooter, hitPart, hitPos)
    -- 1. Type safety
    if typeof(hitPart) ~= "Instance" or not hitPart:IsA("BasePart") then return end
    if typeof(hitPos)  ~= "Vector3" then return end

    -- 2. Magnitude / range check
    local root = shooter.Character and shooter.Character:FindFirstChild("HumanoidRootPart")
    if not root then return end
    if (root.Position - hitPos).Magnitude > MAX_RANGE * 1.15 then return end  -- 15% latency buffer

    -- 3. Identify victim
    local hitChar  = hitPart:FindFirstAncestorOfClass("Model")
    local victim   = game.Players:GetPlayerFromCharacter(hitChar)
    if not victim or victim == shooter then return end

    local humanoid = hitChar:FindFirstChildOfClass("Humanoid")
    if not humanoid or humanoid.Health <= 0 then return end

    -- 4. Optional: server-side confirmatory raycast
    local sParams = RaycastParams.new()
    sParams.FilterDescendantsInstances = {shooter.Character}
    sParams.FilterType = Enum.RaycastFilterType.Exclude
    local dir    = (hitPos - root.Position)
    local sResult = workspace:Raycast(root.Position, dir, sParams)
    if sResult and sResult.Instance:IsDescendantOf(hitChar) then
        humanoid:TakeDamage(MAX_DAMAGE)
    end
end)

When working on a system with client-side hit detection, basic sanity checks on the server — like magnitude checks — are essential to make sure hits are legit. For competitive games, the confirmatory server raycast in step 4 is highly recommended.


5. Common Pitfalls

Shooter hits themselves — Always add the full Character model (not just HumanoidRootPart) to your exclusion list. Accessories and hat parts are separate BasePart instances that the ray can still hit.

Ray fires but hits nothing — Check that your direction vector is scaled by weapon range (e.g. .Unit * 500). A raw unit vector only casts 1 stud.

FastCast bullet spawns below the barrel — Usually caused by an unanchored view model experiencing physics gravity. Parent cosmetic bullets to a plain Folder in Workspace rather than to the tool.

High fire rate floods the server — The common method is to shoot a ray from the client and another from the server via a remote event, but with automatic guns that have a very high fire rate, many remote events would have to be fired for each player. For automatic weapons, batch hit reports every 0.1–0.2 s instead of one event per bullet.

FilterDescendantsInstances vs. ExcludeInstances confusion — Roblox has added RaycastParams.ExcludeInstances and RaycastParams.IncludeInstances as simpler, more flexible APIs to supersede FilterDescendantsInstances for raycasts and other spatial queries. The old pattern still works, but prefer the new one for any new code.


6. Which Approach to Use?

ScenarioMethod
Instant-hit rifle / laser / shotgunWorkspace:Raycast() hitscan
Arrow, grenade, rocket with arcFastCast + Acceleration
Melee swing detectionMultiple raycasts along blade per RunService.Stepped
AoE / splash detectionworkspace:GetPartBoundsInRadius() / SphereCast

FAQ

Q: Client or server raycast? Cast on the client for responsiveness, validate on the server before dealing damage. Pure server-side casting adds noticeable input lag.

Q: Is FastCast still maintained? The core module has been stable for years and is widely used in shipped games. It's open source, so you can fork it if needed.

Q: Can I use ExcludeInstances with FastCast? Yes — FastCast accepts any RaycastParams object you construct, new API included.

Q: Where can I find a complete working example? The GM Market marketplace has Roblox combat scripts that pair FastCast with server-side validation, useful as a reference if you want to study a full system before building your own.


Sources: Roblox Creator Hub — Hit Detection with Lasers · RaycastParams API · New Spatial Query Filters · FastCast thread

0

0 Replies

No replies yet — be the first to respond.