I have successfully added spread to my ranged weapons, though this spread is not very good as when I set the spread value to 1, this makes the weapons spread too hight. When I put the weapons spread below 1 it will completely negate the spread so you have pinpoint accuracy.

This is how my Raycast code looks:

``````local accurateRay = Ray.new(Head, (mousePos - Head).unit * 400)
local Part, Position, Vector = game.Workspace:FindPartOnRay(ray, player.Character)
local Distance = (muzzlePos - Position).magnitude
``````

Here are two gifs.

Spread at the value of 1:
https://gyazo.com/fd37172b05a52e19abf8cc3f53d49d34

Spread at the value of 0.9999:
https://gyazo.com/09418fc7bcb65674e930543286249ed5

Any help to stop this problem occurring would be much appreciated.

1 Like

math.random needs an integer representation (the numbers that is), it means you canâ€™t do math.random(-.9,.9), in that case what you can do is :

``````local spread = 0.98
``````

(This is probably not the best to do tbh, but since nobody is replying decided to do so)

Oh and in your script itâ€™d look like this :

``````Spread = Spread * 100
1 Like

As a note to @MagikTheDogâ€™s answer, math.random without arguments returns a value between 0 and 1, meaning you can also do `(math.random()*2-1)*spread`

1 Like

I found the `randomSpread` function on a different post. It takes an origin cframe that has the position and is facing toward the target, and returns a cframe that you can get the `.LookVector` of to get the offsetted direction. I added the `lookAt` function at the top so you can easily create the origin cframe.

Note: I used `.fromMatrix()` because `.new(pos, look)` is deprecated.

``````local RANGE = 400
local TAU = math.pi * 2
local UP_VECTOR = Vector3.new(0, 1, 0)

local function lookAt(pos, look)
local forwardVector = (pos - look).Unit
local rightVector = forwardVector:Cross(UP_VECTOR)
local upVector = rightVector:Cross(forwardVector)
return CFrame.fromMatrix(pos, rightVector, upVector)
end

local targetCFrame = cframe * CFrame.new(0, 0, -RANGE)
* CFrame.Angles(0, 0, TAU * math.random())
* CFrame.new(0, math.random() * spreadDiameter / 2, 0)
return lookAt(cframe.Position, targetCFrame.Position)
end
``````

Also, I recommend using `workspace:Raycast()` over `workspace:FindPartOnRay()` because you donâ€™t have to create a ray object every time you want to use it.

Imo, this is the best way to do spread. The code is also more efficient.

1 Like

is this the code you were referencing?

``````local rng_v = Random.new()

function RandomVectorOffset(v, maxAngle) --returns uniformly-distributed random unit vector no more than maxAngle radians away from v
return (CFrame.new(Vector3.new(), v)*CFrame.Angles(0, 0, rng_v:NextNumber(0, 2*math.pi))*CFrame.Angles(math.acos(rng_v:NextNumber(math.cos(maxAngle), 1)), 0, 0)).LookVector
end
``````

I agree that this is better, but you should use `.fromMatrix()` in this function because `.new(pos, look)` is deprecated.

I would but it runs faster this way. I also still think that method was wrongly deprecated (or at least, could be improved on). (Update 2021: Replace with CFrame.lookAt which is itâ€™s replacement.)

1 Like