How to make spread for raycast?

I want to make a spread for my raycast weapons, but I haven’t really figured out how to do it yet.
I want to make it so that when the player shoots, the spread increases and the camera wobbles, but I have no idea how to do this.

Local script:

local tool = script.Parent
local Ammo = tool:WaitForChild("Ammo")
local MaxAmmo = tool:WaitForChild("MaxAmmo")
local isReloading = false

tool.Fire.OnServerEvent:Connect(function(player, mouseHit, rate)
	if script.Parent.CanFire.Value == false then
		script.Parent.CanFire.Value = true
		Ammo.Value = Ammo.Value - 1
		local fires = tool.Handle.Fire:Clone()
		fires.Parent = tool.Handle
		fires:Play()
		local ray = Ray.new(tool.Handle.GunFirePoint.WorldCFrame.p, (mouseHit.p - tool.Handle.GunFirePoint.WorldCFrame.p).unit * 300)
		local hit, position, normal = game.Workspace:FindPartOnRay(ray, player.Character, false, true)
		local distance = (position - tool.Handle.GunFirePoint.WorldCFrame.p).magnitude
		local part = Instance.new("Part")
		part.Name = "Bullet"
		part.Anchored = true
		part.CanCollide = false
		part.Material = "Neon"
		part.BrickColor = BrickColor.new("Gold")
		part.Size = Vector3.new(0.1, 0.1, distance)
		part.CFrame = CFrame.new(position, tool.Handle.GunFirePoint.WorldCFrame.p) * CFrame.new(0, 0, - distance / 2)
		part.Parent = workspace
		if hit and hit.Parent ~= workspace.BulletHoles then
			if hit.Parent and hit.Parent ~= workspace.BulletHoles then

					local hole = game.ReplicatedStorage.Concrete:Clone()
					hole.Name = "Bullet Hole"
					hole.Parent = workspace.BulletHoles
					hole.Position = mouseHit.p
					hole.CFrame = CFrame.new(position, position + normal)

					local weld = Instance.new("Weld")
					weld.Part0, weld.Part1 = hit,hole
					weld.C0 = hit.CFrame:Inverse()
					weld.C1 = hole.CFrame:Inverse()
					weld.Parent = hole

					game:GetService("Debris"):AddItem(hole, 8)
					if hit.Parent:FindFirstChild("Humanoid") and hit.Name == "Head"  then
						hole:Destroy()
						hit.Parent.Humanoid:TakeDamage(math.random(137,168))
					end
					if hit.Parent:FindFirstChild("Humanoid") then
						hole:Destroy()
						hit.Parent.Humanoid:TakeDamage(math.random(34,63))
					elseif hit.Parent:FindFirstChild("Humanoid") and hit.Name == "Left Leg" or hit.Name == "Right Leg" then
						hole:Destroy()
						hit.Parent.Humanoid:TakeDamage(math.random(23,45))
				end
			end
		end
		game:GetService("Debris"):AddItem(part, 0.03)
	end
	wait(rate)
	script.Parent.CanFire.Value = false
end)

local reloadSound = tool.Handle.Reload

local function reload()
	if isReloading == false and Ammo.Value < MaxAmmo.Value then
		script.Parent.CanFire.Value = true
		reloadSound:Play()
		isReloading = true
		wait(2)
		isReloading = false
		script.Parent.CanFire.Value = false
		tool.Ammo.Value = MaxAmmo.Value
	end
end

tool.Reloading.OnServerEvent:Connect(reload)
tool.Unequipped:Connect(function()
	isReloading = false
end)

Server script:

local tool = script.Parent
local Ammo = tool:WaitForChild("Ammo")
local MaxAmmo = tool:WaitForChild("MaxAmmo")
local isReloading = false

tool.Fire.OnServerEvent:Connect(function(player, mouseHit, rate)
	if script.Parent.CanFire.Value == false then
		script.Parent.CanFire.Value = true
		Ammo.Value = Ammo.Value - 1
		local fires = tool.Handle.Fire:Clone()
		fires.Parent = tool.Handle
		fires:Play()
		local ray = Ray.new(tool.Handle.GunFirePoint.WorldCFrame.p, (mouseHit.p - tool.Handle.GunFirePoint.WorldCFrame.p).unit * 300)
		local hit, position, normal = game.Workspace:FindPartOnRay(ray, player.Character, false, true)
		local distance = (position - tool.Handle.GunFirePoint.WorldCFrame.p).magnitude
		local part = Instance.new("Part")
		part.Name = "Bullet"
		part.Anchored = true
		part.CanCollide = false
		part.Material = "Neon"
		part.BrickColor = BrickColor.new("Gold")
		part.Size = Vector3.new(0.1, 0.1, distance)
		part.CFrame = CFrame.new(position, tool.Handle.GunFirePoint.WorldCFrame.p) * CFrame.new(0, 0, - distance / 2)
		part.Parent = workspace
		if hit and hit.Parent ~= workspace.BulletHoles then
			if hit.Parent and hit.Parent ~= workspace.BulletHoles then

					local hole = game.ReplicatedStorage.Concrete:Clone()
					hole.Name = "Bullet Hole"
					hole.Parent = workspace.BulletHoles
					hole.Position = mouseHit.p
					hole.CFrame = CFrame.new(position, position + normal)

					local weld = Instance.new("Weld")
					weld.Part0, weld.Part1 = hit,hole
					weld.C0 = hit.CFrame:Inverse()
					weld.C1 = hole.CFrame:Inverse()
					weld.Parent = hole

					game:GetService("Debris"):AddItem(hole, 8)
					if hit.Parent:FindFirstChild("Humanoid") and hit.Name == "Head"  then
						hole:Destroy()
						hit.Parent.Humanoid:TakeDamage(math.random(137,168))
					end
					if hit.Parent:FindFirstChild("Humanoid") then
						hole:Destroy()
						hit.Parent.Humanoid:TakeDamage(math.random(34,63))
					elseif hit.Parent:FindFirstChild("Humanoid") and hit.Name == "Left Leg" or hit.Name == "Right Leg" then
						hole:Destroy()
						hit.Parent.Humanoid:TakeDamage(math.random(23,45))
				end
			end
		end
		game:GetService("Debris"):AddItem(part, 0.03)
	end
	wait(rate)
	script.Parent.CanFire.Value = false
end)

local reloadSound = tool.Handle.Reload

local function reload()
	if isReloading == false and Ammo.Value < MaxAmmo.Value then
		script.Parent.CanFire.Value = true
		reloadSound:Play()
		isReloading = true
		wait(2)
		isReloading = false
		script.Parent.CanFire.Value = false
		tool.Ammo.Value = MaxAmmo.Value
	end
end

tool.Reloading.OnServerEvent:Connect(reload)
tool.Unequipped:Connect(function()
	isReloading = false
end)

(Please make a script and explain the lines to me. I don’t know much programming)

1 Like

In raytracing to produce a spread of rays we have a value from -0.5 to 0.5 (uv) which is basically just the pixel position / the resolution - 0.5. Then we say that the direction is equal to

(Vector3.new(uv.x*spread, uv.y*spread, 1).Unit*range)

You don’t have to go through each pixel, but rather have a resolution value in a sense then for loop that. Say we have 20 resolution to derive uv I do

for x=1,20 do
  for z=1,20 do
    local uv = Vector2.new(x/20, z/20)
  end
end
2 Likes

I didn’t really understand how this can be added to the script because I don’t have a local spread and local range.
Please do this in my script, so that I understand what else needs to be added to the script, it is clear in principle, but it is not clear how to add it to the script.
Thanks.

local tool = script.Parent
local Ammo = tool:WaitForChild("Ammo")
local MaxAmmo = tool:WaitForChild("MaxAmmo")
local isReloading = false

tool.Fire.OnServerEvent:Connect(function(player, mouseHit, rate)
	if script.Parent.CanFire.Value == false then
		script.Parent.CanFire.Value = true
		Ammo.Value = Ammo.Value - 1
		local fires = tool.Handle.Fire:Clone()
		fires.Parent = tool.Handle
		fires:Play()
		for x=1,20 do
  for z=1,20 do
    local uv = Vector2.new((x/20)-0.5, (z/20)-0.5)
    local originOfRay = tool.Handle.GunFirePoint.WorldCFrame.p
    local spread = 5
    local firstComp = mouseHit.p+Vector3.new(uv.x*spread, uv.y*spread, 1).unit
    local direction = (firstComp - tool.Handle.GunFirePoint.WorldCFrame.p) --Vectors can be created from 2 points, say the origin of where that vector is is the thing you are subtracting and the place your vector points to is the first part.

		local ray = Ray.new(tool.Handle.GunFirePoint.WorldCFrame.p, direction.unit * 300)

		local hit, position, normal = game.Workspace:FindPartOnRay(ray, player.Character, false, true)
		local distance = (position - tool.Handle.GunFirePoint.WorldCFrame.p).magnitude
		local part = Instance.new("Part")
		part.Name = "Bullet"
		part.Anchored = true
		part.CanCollide = false
		part.Material = "Neon"
		part.BrickColor = BrickColor.new("Gold")
		part.Size = Vector3.new(0.1, 0.1, distance)
		part.CFrame = CFrame.new(position, tool.Handle.GunFirePoint.WorldCFrame.p) * CFrame.new(0, 0, - distance / 2)
		part.Parent = workspace
		if hit and hit.Parent ~= workspace.BulletHoles then
			if hit.Parent and hit.Parent ~= workspace.BulletHoles then

					local hole = game.ReplicatedStorage.Concrete:Clone()
					hole.Name = "Bullet Hole"
					hole.Parent = workspace.BulletHoles
					hole.Position = mouseHit.p
					hole.CFrame = CFrame.new(position, position + normal)

					local weld = Instance.new("Weld")
					weld.Part0, weld.Part1 = hit,hole
					weld.C0 = hit.CFrame:Inverse()
					weld.C1 = hole.CFrame:Inverse()
					weld.Parent = hole

					game:GetService("Debris"):AddItem(hole, 8)
					if hit.Parent:FindFirstChild("Humanoid") and hit.Name == "Head"  then
						hole:Destroy()
						hit.Parent.Humanoid:TakeDamage(math.random(137,168))
					end
					if hit.Parent:FindFirstChild("Humanoid") then
						hole:Destroy()
						hit.Parent.Humanoid:TakeDamage(math.random(34,63))
					elseif hit.Parent:FindFirstChild("Humanoid") and hit.Name == "Left Leg" or hit.Name == "Right Leg" then
						hole:Destroy()
						hit.Parent.Humanoid:TakeDamage(math.random(23,45))
				end
			end
		end
		game:GetService("Debris"):AddItem(part, 0.03)
		  end
end
	end
	wait(rate)
	script.Parent.CanFire.Value = false
end)

local reloadSound = tool.Handle.Reload

local function reload()
	if isReloading == false and Ammo.Value < MaxAmmo.Value then
		script.Parent.CanFire.Value = true
		reloadSound:Play()
		isReloading = true
		wait(2)
		isReloading = false
		script.Parent.CanFire.Value = false
		tool.Ammo.Value = MaxAmmo.Value
	end
end

tool.Reloading.OnServerEvent:Connect(reload)
tool.Unequipped:Connect(function()
	isReloading = false
end)

Note: I havent tested this so some kid might be like “no, that is definitely not how you would do it” seeing as you use deprecated methods.

Im not good programmer, im teached by old tutorials.

That’s why I’m asking you to do it in my script, because I don’t know much about it and I learned from old tutorials… I won’t blame you if it doesn’t work. I learn from mistakes.