How can I add a spread to a look vector?

I know there’s a topic exactly like this one, but it didn’t have anything marked as a solution and both of the answers didn’t work for me.

This picture shows what I want
image
I’m using a part’s look vector, but don’t know how to randomize it.

heres a simple way, using raycasting (because i assume you are using this for a gun of the sort)

-- origin can be your lookvector, it doesn't matter too much, it just needs to be a position
local Spread = 5 -- in studs, large amound so you know it more noticable
local mouseposition = player:GetMouse.Hit.Position -- get the position of the mouse's position in 3d space
local offset = Vector3.new(math.random(-Spread,Spread),math.random(-Spread,Spread),math.random(-Spread,Spread))
mouseposition = mouseposition + offset -- add the offset to the end position ( in this case the mouse position)
local Direction = (mouseposition - origin).Unit -- direction 

local rayresult = workspace:Raycast(origin,direction*100,raycastparams) -- all together now, cast the ray!
print(rayresult.Position) -- print the position
1 Like

sorry for the late reply, it didn’t send me a notification. I can’t really use the mouse, since its going to be on a normal server script in a part. Im using the parts look vector, so Im not sure how I can add the offset to it.

I’m not sure if it would work, but try using the origin as the parts position, then have the “endposition” as the lookvector, maybe that will make it cast forward

sadly not, it just returns nothing. I set the origin to the position and the “mouseposition” to the lookvector

any other ideas on how to get the hit position of the parts look vector?

Here’s a similar question I answered a few days ago:

so I managed to implement it, and it works just fine, but there’s just one issue.
I run it 100 times and the uh, “water”, randomizes in the same exact location.




I am using an for i = 1,100 do loop.

Could you share your code? I’m pretty sure I tested this and it worked fine

So you managed to make it loop and it randomizes every time? I even added a wait(1) and it still went to the same location.

Sorry for a bunch of commented lines, that’s just stuff that never worked.

local part1 = script.Parent

-- axis: center line of cone
-- angle: angle from center to edge of cone
-- returns: a random unit vector inside the cone, evenly distributed along the partial surface of a unit sphere.
local function RandomCone(axis: Vector3, angle: number)
	local cosAngle = math.cos(angle)
	local z = 1 - math.random()*(1 - cosAngle)
	local phi = math.random()*math.pi*2
	local r = math.sqrt(1 - z*z)
	local x = r * math.cos(phi)
	local y = r * math.sin(phi)
	local vec = Vector3.new(x, y, z)
	if axis.Z > 0.9999 then
		return vec
	elseif axis.Z < -0.9999 then
		return -vec
	end
	local orth = Vector3.zAxis:Cross(axis)
	local rot = math.acos(axis:Dot(Vector3.zAxis))
	return CFrame.fromAxisAngle(orth, rot) * vec
end

local function GetPartsInFrontRay(start)
	local params = RaycastParams.new()
	params.FilterDescendantsInstances = {start}
	params.FilterType = Enum.RaycastFilterType.Blacklist

	local vector = part1.CFrame.LookVector
	--local origin = part1.Position
	---- origin can be your lookvector, it doesn't matter too much, it just needs to be a position
	--local Spread = 5 -- in studs, large amound so you know it more noticable
	----local mouseposition = player:GetMouse.Hit.Position -- get the position of the mouse's position in 3d space
	--local mouseposition = part1.CFrame.LookVector
	--local offset = Vector3.new(math.random(-Spread,Spread),math.random(-Spread,Spread),math.random(-Spread,Spread))
	--mouseposition = mouseposition + offset -- add the offset to the end position ( in this case the mouse position)
	--local Direction = (mouseposition - origin).Unit -- direction 

	--local rayresult = workspace:Raycast(origin,direction*100,raycastparams) -- all together now, cast the ray!

	-- angle of the cone, i.e. the largest angle off the firing axis you could be
	local SPREAD = math.rad(15)

	-- speed of the bullet (can also be random if you want)

	--part1.AssemblyLinearVelocity = RandomCone(part1.CFrame.LookVector, SPREAD)

	local ray = workspace:Raycast(start.Position, RandomCone(part1.CFrame.LookVector, SPREAD) * 15, params)

	if ray and ray.Instance then
		return ray.Instance,ray.Normal,ray.Position
	end
end 

local part,normal,pos = GetPartsInFrontRay(part1)




for i = 1,100 do
	if part then
		warn(part.Name,normal)
		local water = game.ReplicatedStorage.water:Clone()
		water.Parent = workspace
		water.CFrame = CFrame.new(pos, pos+normal)
		water.WeldConstraint.Part1 = part
	else
		print("ugh")
	end
end

Well, you’re only calling GetPartsInFrontOfRay once, and reusing the result 100 times.

Call it inside the loop to randomize every time.

2 Likes

It’s not too complicated. Assuming you have a CFrame, you only need to add an angle to it. local yourCFrameValue = CFrame.lookAt(yourCFrameValue.Position, yourCFrameValue.LookVector, yourCFrameValue.UpVector) * CFrame.Angles(randomangle.X, randomangle.Y, randomangle.Z)
“randomangle” is your random angle in radians.

1 Like

just multiply raycast cframe by random cframe angles like:

client:

local cam=workspace.CurrentCamera
local pwr=5
local spread=CFrame.Angles(math.rad(math.random(-pwr,pwr),math.rad(math.random(-pwr,pwr),math.rad(math.random(-pwr,pwr))

yourevent:FireServer(cam.CFrame.Position,cam.Focus.Position,spread)

server:

yourevent.OnServerEvent:Connect(function(plr,pos,dir,spread)
local rayCast=Ray.new(pos,CFrame.new(pos,dir)*spread).LookVector.unit*1000)
--or not 'Ray.new' but 'workspace:Raycast'
end)

taking into account that the shot will be from the center of the screen, that is on phones the shot will be normal

Sorry this is a bit random, but I’m just wondering if it’s possible to get the angle in the cone that the direction is in? im wondering if I can get a value that gets smaller the farther it is away from the center
kinda like this:
Untitled (2)
(red being the angle)

Well, the r variable inside that function tells you “how far away from the center line, in studs, the tip of the arrow is”. So you could return r that from the function as well, if you like.

If you genuinely need the angle and not the distance, return math.asin(r) instead.