Distance to Edge of Circle From Point In Circle - NPC Wandering Within Bounds

I have an NPC who can “wander” from an origin point.

  1. Blue is the origin
  2. Yellow is the “npc”
  3. Red is the radial limit the NPC can travel within

image

I want to be able to take the NPC’s (yellow) current position and generate directions (2D, ignore the Y axis) all around it. However, the directions must have a length that does not extend outwards from - say - 20 studs from the origin (Blue).

I do not want the NPC to be able to wander outside the circle (20 studs) from the center origin.

image

image

Given

local origin = Vector2.new(10,10)
local currentPosition = Vector2.new(15,0)
local maxRadiusAroundOrigin = 20

How can I generate a set of directions around the currentPosition that have lengths that would not extend 20 studs past the origin? The amount of directions generated is arbitrary. I will choose to generate 5 or 100 directions around the currentPosition. That part doesn’t matter.

2 Likes

You could have some code which checks the magnitude between the orginpart and the NPC’S torso if the magnitude between them is greater then 100 (as the radius) then it’ll move back to the circle. This might not work but here’s an example.

if (game.Workspace.NPC.Torso.Position - game.Workspace.OrginPart.Position).magnitude >= distance then
game.Workspace.NPC.Humanoid:MoveTo(game.Workspace.OrginPart.Position)
2 Likes

Hey, thanks for the reply.

I’d like to have a mathematical solution that doesn’t rely on this because I have about 100 NPCs utilizing this and I’d rather not have to check them every certain amount of time while they are moving. I’ll keep this in mind if I absolutely can’t find a solution though.

Wouldn’t the mathematical solution also require checking every certain amount of time?

local radius = 8;

local function getDirections(n,point,center)
 local directions = {};
  for i=0,n,1 do
    local angle =  i / n  * math.pi * 2  
    local yDist = math.sin(angle) * radius
    local zDist = math.cos(angle) * radius

    local edgePoint = center + Vector3.new(yDist,center.y,zDist);
    directions[#directions + 1] = (edgePoint - point) -- If you want the length to the edge, take the magnitude of this
  end
  return directions
end

Something like this may work

2 Likes

Not necessarily. There is a relationship between a point in the circle and the edge from the origin. I just haven’t figured it out yet. That way I could tell the NPC where to go without going out of the circle. The exact point where to go.

You might want to look into parabolic functions and the equations of an ellipse/circle then. These would give actual functions for the values of the ellipse, and you can use an inequality to get the set of points which satisfy the equation within that ellipse or circle.

This code will allow an NPC to wander around themself, but not outside the bounds of their origin. It works by generating wanderpoints, and checking if they are within range of the origin. If it fails to find a point 10 times, the NPC will likely need to be reset.

local NPC_HumanoidRootPart = script.Parent.NPC
local spawnOrigin = Vector3.new(0,0,0)	--script.Parent.SpawnLocation.Position
local rng = Random.new()
local tau = math.pi*2


local MAX_WANDER_RANGE = 30				-- Studs from origin
local WANDER_DISTANCE = 12				-- Distance from current location that NPC can wander
local AVERAGE_WANDER_WAIT = 7			-- NPC decides to wander this often on average
local WANDER_LOCATION_ATTEMPTS = 10		-- How many attempts NPC will try to find a wander point before resetting.



while true do

	wait(AVERAGE_WANDER_WAIT * rng:NextNumber(.5,1.5))

	local wanderPoint = nil
	for i=1, WANDER_LOCATION_ATTEMPTS do
		-- wanderPointAttempt = NPC current location + (random angle * random distance)
		local wanderPointAttempt = NPC_HumanoidRootPart.Position + (
			CFrame.Angles(0,tau*rng:NextNumber(0,1),0) * CFrame.new(0,0,(rng:NextNumber(0,1)^.5)*WANDER_DISTANCE)
		).p
		-- Check if new point is inside of originRange
		if (spawnOrigin-wanderPointAttempt).magnitude < MAX_WANDER_RANGE then
			wanderPoint = wanderPointAttempt
			break	-- No more attempts, we've found a valid point
		end
	end

	if wanderPoint then
		--todo: move NPC to wanderPoint
	else
		--todo: unable to find a wanderpoint. Either reset NPC or have them walk to origin.
	end
end

If you do not care about the NPC wandering around itself, then you could simply choose random points inside of the origin. With this method, you don’t need to use any kind of attempts since all points would be valid. Just use the code that generates a point around the NPC to generate a point around the origin instead.

1 Like

Does it matter if the directions are perfectly divided by x degrees around npc or not?

If not then just generate a random postition within radius from center then calculate direction using that point. (This would favour walking towards the center rather than the edge tho)

1 Like

So it seems that both you and @Xx1Luffy1xX were on the right track here and you put it simply into words.

The solution is to, as StonksMcHat said:

  1. Get the directions needed
  2. Find the end points by starting from the center and moving in the current iterated direction multiplied by the circle’s radius
  3. You now have a set of points on the edge of the circle
  4. Get the distance to each point from the current NPC location and manipulate it if desired

The result is below (WebM, sorry iOS mobile users)

3 Likes