I’m pretty bad at scripting guns in general, so this is a challenge for me. I was wondering how I could add ‘spread’ to the bullet that is fired from the gun. Right now this is how I’m handling the bullet creation:

local function renderLocalBullet(dataArray)
local startPos = dataArray[1]
local endPos = dataArray[2]
local brickColor = dataArray[3]
local newBullet = Instance.new('Part')
newBullet.BrickColor = brickColor
newBullet.Transparency = 0.5
newBullet.Reflectance = 0
newBullet.Material = Enum.Material.Neon
newBullet.Anchored = true
newBullet.Locked = true
newBullet.CanCollide = false
newBullet.Size = Vector3.new(.1, .1, (startPos - endPos).magnitude)
newBullet.CFrame = CFrame.new(startPos, endPos) * CFrame.new(0, 0, -newBullet.Size.z / 2)
newBullet.Parent = workspaceService
debrisService:AddItem(newBullet, 0.05)
end

The dataArray is as follows:

local startPos = localCharacter:WaitForChild('Head').CFrame.p
local mousePos = localMouse.Hit.p
local hitPart, hitPosition = workspaceService:FindPartOnRay(Ray.new(startPos, (mousePos - startPos).unit * 999), localCharacter)
renderLocalBullet({newTool.Barrel.Position, hitPosition, localPlayer.TeamColor})

Any help would be appreciated as I’ve been trying to do this for a while with no result, end goal is to create a variable called ‘bulletSpread’ that will be a multiplier of sorts of how much spread there is on the gun.

You can store the bullet spread as some parameters for a distribution. Then use those parameters to generate an angular spread from that distribution, via CFrame.Angles.

In the simplest case, the distribution is uniform, so that you can compute the direction vector with spread applied as CFrame.Angles(sy*r1,sx*r2,0)*mDirection with r1,r2 taking values in the interval (1,1) (you could generate them with the formula 2*math.random()-1).

If you want something somewhat more realistic, you can sample the random values from a normal distribution (i.e. bell curve) or an approximation to a normal distribution. In this case, the relevant parameter is the standard deviation of the normal distribution. In general, bullets will tend to hit closer to the center on average, while still being random.

My bad. Basically, you can use CFrames to rotate the path of the ray by an angle. For each bullet the angle is random, but for a simple raycasting gun the angle can be computed as (2*math.random()-1)*maxSpreadAngle.

Alternatively, if you wanted the bullet spread to be circular, you could generate the CFrame like so: cframe = CFrame.Angles(math.random()*maxSpreadAngle,0,2*math.pi*math.random()). This is equivalent to setting the direction of the spread to a random angle, then applying a random spread.

I would apply the bullet spread to endPos, i.e. endPos = startPos+cframe:VectorToWorldSpace(endPos-startPos). Then everything else is calculated automatically.

Also, it looks like you’re trying to apply a 10 degree spread, but CFrame.Angles accepts its arguments in radians, so you want the multiplier to be math.rad(10).

I think I screwed up, although I’m not sure if this is causing that bizarre behavior. Try computing cframe as CFrame.Angles(0,0,z)*CFrame.Angles(x,0,0).

Okay, so first of all you should be applying the bullet spread before you do the raycasting, otherwise your bullet and your ray don’t match. In other words, you want to apply the spread to mousePos, then cast the ray.
Actually, since you have a bullet spread, the bullet no longer lands at mousePos, which means you have to extend the Ray instead of relying on it terminating at mousePos.

Secondly, I messed up by not converting to world coordinates. You should cast the ray in the direction CFrame.new(startPos,mousePos):ToWorldSpace(CFrame.Angles(0,0,Z)*CFrame.new(X,0,0)).lookVector. X and Z are the same as before in the definition of ‘cframe’.