How can I raycast in every direction from a position?

Pretty much I want to raycast many directions from a position basically spreading out to cover as much area as possible. I want to be able to have a number of raycasts. E.g 10 or 5 and it will spread them out as much as possible. I’m mainly having trouble getting the directions. How should I go about doing this? Any help is greatly appreciated.

2 Likes

What is the application for this, so we can come up with the best solution?

If you know the exact number and its small, you could just hardcode some sensible directions.

Or you could use something like a fibonacci spiral distribution, like shown in this video from 1:44 to like 6:12: Coding Adventure: Boids - YouTube

1 Like

I’m making a projectile in my game. Once it hits a surface I want it to spread out into smaller projectiles in every direction around it.

Watching the video helps me understand a little bit better. I’m still not sure how I would apply this to my own code however.

Here’s an implementation I found on stackoverflow that I ported to lua:

Edit for future readers: see the updated version of this below

My port:

local function EvenlyDistributeVectors(n)
	if n == 0 then return {} end
	if n == 1 then return { Vector3.yAxis } end
	local vecs = table.create(n)
	local phi = math.pi * (3 - math.sqrt(5))
	
	for i = 0, n - 1 do
		local y = 1 - (i / (n - 1)) * 2
		local radius = math.sqrt(1 - y * y)
		
		local theta = phi * i
		vecs[i+1] = Vector3.new(
			math.cos(theta) * radius,
			y,
			math.sin(theta) * radius
		)
	end
	return vecs
end

That returns an array of vectors evenly distributed on a unit sphere.

7 Likes

You might also be interested in generating a random vector inside of a given cone:

1 Like

this is what i tried, and it looks like it worked perfectly.

local cf = script.Parent.CFrame

for i = 1,360/10 do
	local ray = workspace:Raycast(script.Parent.Position,cf * CFrame.new(Vector3.new(5,30,0)).Position - script.Parent.Position)
	print(ray.Position)
	local ins = Instance.new("Part")
	ins.Size = Vector3.new(1,1,1)
	ins.Position = ray.Position
	ins.Anchored = true
	ins.CanCollide = false
	ins.CanQuery = false
	ins.Parent = workspace
	cf *= CFrame.fromOrientation(0,i,0)
end

this is the result:


this is a ray that is cast from the ground so i made the direction’s Y axis positive. i see that you want rays that spread outwards from the centre object so you can make the Y axis 0.

forgot to add a note: this only creates a 2D circle and not a 3D sphere like the one you want. to achieve casting rays in every direction, you can use this code and repeat it a number of times with an offset to the ray Direction.

1 Like

Gonna try these out. Will update you on how it goes. I appreciate the help a lot!

Works perfectly! Thank you so much I’ve been struggling with this for a while.

Is there anyway to get specific points in the cone rather than a random point. Similar to the circle raycasts but with the cone.

Can you give an example of what you mean? And which of the two options are you using?

1 Like

I used the raycast in every direction in a circle for something in my game. I also want to do something similar except I want the projectiles to be in a cone or half-circle almost shooting away from the player instead of in every direction. Like this:
image
The black dot being the player and the red lines being the rays in the cone. I want to be able to input a number similar to the circle and get multiple directions within that cone.

The difference between the cone raycasting you sent me and the version I want is that the one you sent gets a random direction. I want to be able to get multiple directions evenly spread out in the cone if that makes sense.

1 Like

This should work for you. You’ll have to rotate the generated vectors, because this just assumes you want the cone pointed in the “world -Z axis direction”. That should make it easy because you can e.g. do part.CFrame * vec on each vector to point the cone in the same direction as part.LookVector.

That or you can take the last half of the RandomCone method above to rotate them inside the function.

-- generates vectors in a cone whose axis is the -Z axis
-- n: number of vectors to generate
-- angle: angle between the -Z axis and the edge of the cone
local function EvenlyDistributeVectorsInCone(n, angle)
	if n == 0 then return {} end
	if n == 1 then return { -Vector3.zAxis } end
	local cosAngle = math.cos(angle)
	local vecs = table.create(n)
	local phi = math.pi * (3 - math.sqrt(5))

	for i = 0, n - 1 do
		local a = i / (n - 1)
		local z = -1 + (1-cosAngle)*a
		local radius = math.sqrt(1 - z * z)

		local theta = phi * i
		vecs[i+1] = Vector3.new(
			math.cos(theta) * radius,
			math.sin(theta) * radius,
			z
		)
	end
	return vecs
end
1 Like

Will try this when I get the chance! Thank you so much for all the help!

1 Like

How exactly do I apply the directions? Here is my code:
My cone function (I took the bottom half from the random cone like u suggested)

local function EvenlyDistributeVectorsInCone(n, angle, axis)
	if n == 0 then return {} end
	if n == 1 then return { -Vector3.zAxis } end
	local cosAngle = math.cos(angle)
	local vecs = table.create(n)
	local phi = math.pi * (3 - math.sqrt(5))

	for i = 0, n - 1 do
		local a = i / (n - 1)
		local z = -1 + (1-cosAngle)*a
		local radius = math.sqrt(1 - z * z)

		local theta = phi * i
		
		local vec = Vector3.new(math.cos(theta) * radius,math.sin(theta) * radius,z)
		
		local cancel = false
		
		if axis.Z > 0.9999 then
			cancel = true
		elseif axis.Z < -0.9999 then
			vec = -vec
		end
		
		if cancel == false then
			local orth = Vector3.zAxis:Cross(axis)
			local rot = math.acos(axis:Dot(Vector3.zAxis))
			vec = CFrame.fromAxisAngle(orth, rot) * vec	
		end
		
		vecs[i+1] = vec
	end
	
	return vecs
end

the axis is the humanoidrootpart lookvector but for some reason it considers the cone always to the right of my character. Why is this and how can I fix it?
and heres the code where I use it

local firecount = 5

			local directions = EvenlyDistributeVectorsInCone(firecount,5,char.HumanoidRootPart.CFrame.lookVector)

			for i = 1,firecount do

				local direction2 = directions[i]

				local rc = raycastfire(char,char["Left Arm"].Position - char["Left Arm"].CFrame.upVector*0.5,direction2*10,raycastParams2,blacklisttable2)

				if rc ~= nil then

					SSS.events.ApplyEffect:Fire(rc.Instance,"PlaceFire",{rc.Position,rc.Normal})

				end
			end

Really good attempt, there’s just a few tweaks to some negatives and things you needed. I also cleaned up the if statement stuff but your method also would work.

local function EvenlyDistributeVectorsInCone(n, angle, axis)
	if n == 0 then return {} end
	if n == 1 then return { axis } end
	local cosAngle = math.cos(angle)
	local vecs = table.create(n)
	local phi = math.pi * (3 - math.sqrt(5))

	for i = 0, n - 1 do
		local a = i / (n - 1)
		local z = -1 + (1-cosAngle)*a
		local radius = math.sqrt(1 - z * z)

		local theta = phi * i

		local vec = Vector3.new(math.cos(theta) * radius,math.sin(theta) * radius,z)
		
		if axis.Z > 0.9999 then
			vecs[i+1] = -vec
			continue
		elseif axis.Z < -0.9999 then
			vecs[i+1] = vec
			continue
		end
		
		local orth = -Vector3.zAxis:Cross(axis)
		local rot = math.acos(axis:Dot(-Vector3.zAxis))
		vec = CFrame.fromAxisAngle(orth, rot) * vec	

		vecs[i+1] = vec
	end

	return vecs
end
1 Like