Adding spread to a raycast

I made a pistol. I want it to have some spread. Something like this:

so if the gun is close, it wont really miss but if its far then it has a way higher chance to miss

I managed to do something similar, but the spread is different based on the distance. It is like this:

so if the gun is close, it wont really miss that much, but its the same if its very far away.

I tried this:

local camera = workspace.CurrentCamera
local mousePosition = player:GetMouse().Hit.Position
local MousePositionSpread = mousePosition + Vector3.new(math.random(-spread, spread), math.random(-spread,spread), math.random(-spread,spread))
local range = 100

local direction = (MousePositionSpread - camera.CFrame.p).Unit * range
local ray = Ray.new(camera.CFrame.p, direction)


local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = {gun, player.Character, unpack(lasersToIgnore)}
raycastParams.IgnoreWater = true

local raycastResult = workspace:Raycast(ray.Origin, ray.Direction, raycastParams)
1 Like

This problem happens because you add the spread after calculating the distance, and not before. This means the effective change of the direction vector decreases as the distance that the mouse is placed on is farther. Simple fix is to:

--assuming that the camera points exactly at what to shoot at
local RandomSpreadX = camera.CFrame.RightVector.Unit * math.random() * spread
local RandomSpreadY = camera.CFrame.UpVector.Unit * math.random() * spread

local direction = ((MousePosition - camera.CFrame.p).Unit  + RandomSpreadX + RandomSpreadY) * range

Hope this helps! :grin:

1 Like

you could just…

local camera = workspace.CurrentCamera
local mousePosition = player:GetMouse().Hit.Position
local spreadangle=1 --anything you want
local CF=CFrame.new(camera.CFrame.p,mousePosition)*CFrame.angles(math.rad((math.random()-0.5)*2*spreadangle),math.rad((math.random()-0.5)*2*spreadangle,0))
local range = 100

local ray = Ray.new(CF.Position,CF.LookVector*range)


local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = {gun, player.Character, unpack(lasersToIgnore)}
raycastParams.IgnoreWater = true

local raycastResult = workspace:Raycast(ray.Origin, ray.Direction, raycastParams)

you can fix any typo incase if I missed one as I was doing the edits in here

1 Like

this works but only if the ray hits something. like if it hits nothing, it shoots like in a random direction on the screen. it may be because of this part of the code

local targetPosition
if raycastResult then
	targetPosition = raycastResult.Position
else -- if it is shoot at the sky or the void
	targetPosition = ray.Origin + direction
end

target position is the position is the position where the bullet should go. it works good if there is no spread. how can i make it work with spread?

You can just fetch the CFrame in that case and use that to decide targetPosition. Which would look something like this “targetPosition=CF.Position+CF.LookVector*range” (or dont include range depending on how you use this position)

1 Like

thank you! it works very great! (i always struggle when i deal with cframes. i spend a lot of time learning how to use them and i still suck)

1 Like

(Dont worry mods I’ll delete this later)
No problem. Oh and I think you marked the wrong comment as the solution, just pointing it out for the newcomers that might have to drag down to find a solution to their own problem. You should mark the 2nd comment where I fixed the problem with CFrames so others dont have to drag down, cheers!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.