How to make a character walk to any position within a circle

Hello developers,

I have this problem where I want to have a character walk to any position that’s within a circle.


I can’t just have the character walk to any point between the two red points or else they would be able to walk in the purple.

What is the most efficient way to do this? If you need any more information then I would gladly share it.

Try creating an union to make a circular wall around the circle and use Raycast to send a ray to every direction to detect if they can walk to a certain position or not. By the way you can make the union invisible.

Can’t you just build a invisible wall around the circle?

Getting a random point in a circle involves a bit of trigonometry…

We know that in a circle, the following is true

-- Where x and y make up an edge point on the circle
cos(theta) * radius = x
sin(theta) * radius = y

In order to get a random point within the circle, we need to get a random theta value between 0 and 2 * math.pi, and we also need to get a random radius value between 0 and radius.

We also need to account for a bias where more “random” points tend to end up closer towards the center of the circle. You can read more about that on this thread…

Here is the code I wrote for you

function GetRandomPointInCircle(circle)
   assert( typeof(circle) == "Part", " circle must be a part ")   ​

   local radius = circle.Size.Z / 2
   local cf = circle.CFrame

   local theta = 2 * math.pi * math.random()
   local r = radius * math.sqrt( math.random() )

   return cf.Position + cf.RightVector * math.cos(theta) * r + cf.UpVector * math.sin(theta) * r
end

After finding the random point, im sure you can figure out the rest yourself…

2 Likes

This solution uses a bit of trigonometry, but it works for me.

  1. Get a random angle (90°)
  2. Get a random number between 0 and 1 (0.5)
  3. Get the sine of the angle, then multiply it by the random number and the radius of the circle
  4. Do 3 again, but with cosine
  5. Plug the sine and cosine into a Vector3, with the X being the cosine and Z with the sine
  6. Add the center position of the circle to the vector

You should now have a Vector3 you can make the character walk to!

I second this post. I was actually just now reading that stack overflow page to write an answer. Funny to see someone else was thinking the same thing!

1 Like

Cant you just see if the point is within the magnitude of however big the circle is lol

Edit: This may be inefficient because you need to generate numbers until it meets the requirements

Are the things in parenthesis just for reference? Also, how do I get the random angle? Sorry if I sound dumb, I don’t normally do much with math when scripting.

Do I just get a random number between 1 and 360 or something like that

I tried both @Xx1Luffy1xX’s and @comsurg’s solutions but for some reason they don’t work. I’m not sure what the problem is, but the character just seems to move to the center and then just kinda stays there.

function GetRandomPointInCircle(circle)
    -- the notes are just prints so I could try and find the problem
	local radius = circle.Size.X / 2
	--print(math.random(1,360))
	local randomAngle = math.rad(math.random(1,360))
	--print(randomAngle)
	local randomNum = math.random()
	--print(randomNum)
	
	local sine = math.sin(randomAngle) * randomNum * radius
	local cosine = math.cos(randomAngle) * randomNum * radius
	--print(sine, cosine)
	
	local finalPoint = Vector3.new(cosine, 0, sine) + circle.Position
	return finalPoint
end

local newPoint

while true do
	newPoint = GetRandomPointInCircle(workspace.Circle)
	print(newPoint)
	script.Parent.Humanoid:MoveTo(newPoint)
	print("moving")
	script.Parent.Humanoid.MoveToFinished:Wait()
	print("moved")
end

I might’ve not done the code correctly.

This is actually because the cylinder, which you used to make the circle, has its localized X axis basis vector facing away from the circle. Here is the fix…

function GetRandomPointInCircle(circle)
	local radius = circle.Size.Z / 2
	local cf = circle.CFrame

	local theta = 2 * math.pi * math.random()
	local r = radius * math.sqrt( math.random() )

	return cf.Position + cf.LookVector * math.cos(theta) * r + cf.UpVector * math.sin(theta) * r
end

local newPoint

while true do
	newPoint = GetRandomPointInCircle(workspace.Circle)
	print(newPoint)
	script.Parent.Humanoid:MoveTo(newPoint)
	print("moving")
	script.Parent.Humanoid.MoveToFinished:Wait()
	print("moved")
end

1 Like