Finding the closest player position without .magnitude

but how do i not loop through all of the parts in the region without finding the players

Function for finding nearest player

function findNearestPlayer(players)
  local mob = nil -- reference the mob here
  local mindistance = -- min distance
  local playersinrange = {}
  if not mob then return end
  for _,v in pairs(players) do
     If not v then continue end
     local distance = (mob.PrimaryPart.Position - v.PrimaryPart.Position).magnitude
     If distance <= mindistance then
         playersinrange[v] = distance
     end
   end 
local s = 0
local p = nil
 for i, v in pairs(playersinrange) do
    if v <= s then 
      s = v
      p = i
    end
  end
return p
end
  

       

  

This will give you the nearest player

Im not done with ut i just gonna go do something ima edit it, with the rest in 6 minutes

I gave you the answer for that. Its in the function getPlayerCharacters

I am making it so that there are two areas, with one the enemy cant go in, but once the player goes in the other area, the enemy starts running after the player so i dont think i can use the minimum distance for this

Ohh ok give me a second to tweek it

but when the boss is chasing the player, it will be closer to the player so he will keep on following it out of the area

In order to tell if the player is on one side or the other the easiest way to do that is to have 2 huge parts, that are invisible and cant collide. Then put on at one side and one at the other. Then when the player tpuches the one near the mob, you make the mob chase them. If the touch the one away from the mob, the mob stop chasing them. Your code is wayyy to long for me to do at work, i get off in 5 hours i can do it for you then

I already have that, but i made a region 3 around that part. I probably wont be a wake when you get off of work, its 11pm for me rn, but thankyou a lot! I will try to respond back as quickly as i can

local playerService = game:GetService("Players")

local partMobActivate = nil -- Change this to a reference for the part where the mob attacks
local mob = nil -- Change this to a reference to mob
local playersInAttackRange = {}

local function onTouch(part)
	local humanoid = part.Parent:FindFirstChild("Humanoid")
	if humanoid and part.Parent and mob then
		local player = playerService:GetPlayerFromCharacter(part.Parent)
		if not player then return end
		local distance = (part.Parent.PrimaryPart.Position - mob.PrimaryPart.Position).Magnitude
		playersInAttackRange[player] = distance
	end

end

local function onTouchEnded(part)
	local humanoid = part.Parent:FindFirstChild("Humanoid")
	if humanoid and part.Parent and mob then
		local player = playerService:GetPlayerFromCharacter(part.Parent)
		if not player then return end
		playersInAttackRange[player] = nil
	end
end

partMobActivate.TouchedEnded:Connect(onTouchEnded)
partMobActivate.Touched:Connect(onTouch)

while wait() do
	local player = nil
	local least = nil
	for i, v in pairs(playersInAttackRange) do
		if not least or v <= least then
			player = i
			least = v
		end
	end
        If not player then continue end
	local character = player.Character
	if not character then continue end
	local primaryPart = character.PrimaryPart
	local mobHumanoid = character.Humanoid
	if not primaryPart or not mobHumanoid then continue end
	local location = primaryPart.Position
	mobHumanoid:MoveTo(location)
end

Going to sleep tell me if this doesn’t work, or if there are any problems, I will answer when i wake up

the playersinattackrange is constantly zero even if im touching the part. but i dont know why i also dont know how it knows which one is closer
I had to do some changes to your script because the touch statment was running after the wait loop causing errors. also is there a better way than to use wait(), it makes a lot of lag this is what the script looks like now:

local playerService = game:GetService("Players")

local partMobActivate = script.Parent.Parent["Electric Area"] -- Change this to a reference for the part where the mob attacks
local mob = script.Parent -- Change this to a reference to mob
local playersInAttackRange = {}

local function onTouch(part)
	local humanoid = part.Parent:FindFirstChild("Humanoid")
	if humanoid and part.Parent and mob then
		local player = playerService:GetPlayerFromCharacter(part.Parent)
		if not player then return end
		local distance = (part.Parent.PrimaryPart.Position - mob.PrimaryPart.Position).Magnitude
		playersInAttackRange[player] = distance
		print("touched!!!!!!!!!")
	end

end

local function onTouchEnded(part)
	local humanoid = part.Parent:FindFirstChild("Humanoid")
	if humanoid and part.Parent and mob then
		local player = playerService:GetPlayerFromCharacter(part.Parent)
		if not player then return end
		playersInAttackRange[player] = nil
		print("touchended")
	end
end

partMobActivate.Touched:Connect(onTouch)
partMobActivate.TouchEnded:Connect(onTouchEnded)

while wait() do
	local player = nil
	local least = nil
	if #playersInAttackRange >= 1 then
	for i, v in pairs(playersInAttackRange) do
		if not least or v <= least then
			player = i
			least = v
			print(i, v)
		end
	end
	print(player)
	local character = player.Character or player.CharacterAdded:Wait()
	if not character then continue end
	local primaryPart = character.PrimaryPart
	local mobHumanoid = mob.Humanoid
	if not primaryPart or not mobHumanoid then continue end
	local location = primaryPart.Position
	mobHumanoid:MoveTo(location)
		end
end

Remove if #playersinattackrange

I updated my script also i gotta add something else i just remembered

but if i getrid of this, the loop will run before the touch statment so there will be a nil error, also what did u change

2 things it is working, its just the humanoid:MoveTo isnt working thats the only part that isnt working
proof:


it correctly detects player and its position
also this is the new updated code

local playerService = game:GetService("Players")

local partMobActivate = game.Workspace:WaitForChild("Part1") -- Change this to a reference for the part where the mob attacks
local mob = script.Parent -- Change this to a reference to mob
local playersInAttackRange = {}
local debouncet = {}

local function onTouch(part)
	if debouncet[part.Parent] then return end
	print("touched")
	local humanoid = part.Parent:FindFirstChild("Humanoid")
	if humanoid and part.Parent and mob then
		local player = playerService:GetPlayerFromCharacter(part.Parent)
		if not player then return end
		local distance = (part.Parent.PrimaryPart.Position - mob.PrimaryPart.Position).Magnitude
		playersInAttackRange[player] = distance
		debouncet[part.Parent] = true
	end

end

local function onTouchEnded(part)
	if not debouncet[part.Parent] then return end
	print("touchended")
	local humanoid = part.Parent:FindFirstChild("Humanoid")
	if humanoid and part.Parent and mob then
		local player = playerService:GetPlayerFromCharacter(part.Parent)
		if not player then return end
		playersInAttackRange[player] = nil
		debouncet[part.Parent] = false
	end
end

print(game.Workspace.Part1)
partMobActivate.Touched:Connect(onTouch)
partMobActivate.TouchEnded:Connect(onTouchEnded)


while wait(1) do
	local player = nil
	local least = nil
	for i, v in pairs(playersInAttackRange) do
		print(i, v)
		if not least or v <= least then
			player = i
			least = v
		end
	end
	print(player)
	if not player then continue end
	local character = player.Character
	if not character then continue end
	local primaryPart = character.PrimaryPart
	local mobHumanoid = character.Humanoid
	if not primaryPart or not mobHumanoid then continue end
	local location = primaryPart.Position
	mobHumanoid:MoveTo(location.Unit)
	print(location)
end

try and figure out why the move to isnt working, i gotta go to work, i will research why at work

edit: So the mob should finally move now, but the problem is it moves once then stops working, probably game waiting for moveToFinished im off to work, will continue later

its constantly zero because playersinattackrange is a dictionary, you cant do # for a dictionary, you have to manually get the length buy looping through it

The best solution is to put the magnitudes into a table and then sort the table, returning the smallest distance.

local rig = script.Parent
local electricarea = script.Parent.Parent["Electric Area"]
local range = 100 --maximum distance player can be from boss

local function findNearestPlayer(boss)
	local characters = {}
	for _,player in pairs(game.Players:GetChildren()) do
		if player.Character ~= nil and player.Character:FindFirstChild("HumanoidRootPart") ~= nil then
			local arr  = {}
			arr.Player = player
			arr.Character = player.Character
			arr.Position = player.Character.HumanoidRootPart.Position
			arr.Magnitude = (boss.HumanoidRootPart.Position - player.Character.HumanoidRootPart.Position).magnitude
			if arr.magnitude <= range then
				table.insert(characters,arr)
			end
		end
	end
	table.sort(characters,function(a,b) return a.Magnitude < b.Magnitude end)
	return characters[1]
end

while wait(1) do
	local nearestPlayer = findNearestPlayer(rig)
	rig.Humanoid:MoveTo(nearestPlayer.Position)
	print(nearestPlayer.Magnitude)
end

That wont work cause she wants it to be an area so its not a circle range around the boss

I did some research and the problem resides in the fact that GetPartsInRegion3 is depreciated.

The recommendation is that devs use GetPartBoundsInBox instead.

I wrote this up using that, and everything works as expected.

local rig = script.Parent
local electricarea = script.Parent.Parent["Electric Area"]
local area = {}
area.CFrame = CFrame.new(0,0,0) -- center of arena
area.Size = Vector3.new(100,50,100) -- size of arena
area.OverlapParams = OverlapParams.new()
area.OverlapParams.FilterType = Enum.RaycastFilterType.Whitelist

function getCharactersInArena()
	local whitelist = {}
	for _,player in pairs(game.Players:GetChildren()) do
		if player.Character ~= nil and player.Character:FindFirstChild("HumanoidRootPart") ~= nil then
			table.insert(whitelist,player.Character.HumanoidRootPart)
		end
	end
	area.OverlapParams.FilterDescendantsInstances = whitelist
	local arr = workspace:GetPartBoundsInBox(area.CFrame,area.Size,area.OverlapParams)
	return arr
end

local function findNearestPlayer(boss)
	local characters = {}
	local charactersInArena = getCharactersInArena()
	
	for _,root in pairs(charactersInArena) do
		local player = game.Players:GetPlayerFromCharacter(root.Parent)
		local arr  = {}
		arr.Player = player
		arr.Character = player.Character
		arr.Position = player.Character.HumanoidRootPart.Position
		arr.Magnitude = (boss.HumanoidRootPart.Position - player.Character.HumanoidRootPart.Position).magnitude
		table.insert(characters,arr)
	end
	
	table.sort(characters,function(a,b) return a.Magnitude < b.Magnitude end)
	return characters[1]
end

while wait(1) do
	local root = rig.HumanoidRootPart
	local nearestPlayer = findNearestPlayer(rig)
	if nearestPlayer ~= nil then
		rig.Humanoid:MoveTo(nearestPlayer.Position)
		print(nearestPlayer.Magnitude)
	end
end
1 Like
local function GetClosestCharacter(position)
	local closestPlayer = nil
	local closestMagnitude = math.huge
	for i, player in ipairs(game.Players:GetPlayers()) do
		if player.Character == nil then continue end
		local characterPosition = player.Character:GetPivot().Position
		local magnitude = (characterPosition - position).Magnitude
		if magnitude > closestMagnitude then continue end
		closestPlayer = player
		closestMagnitude = magnitude 
	end
	return closestPlayer, closestMagnitude
end

local function GetCharactersWithin(position, radius)
	local players = {}
	for i, player in ipairs(game.Players:GetPlayers()) do
		if player.Character == nil then continue end
		local characterPosition = player.Character:GetPivot().Position
		if (characterPosition - position).Magnitude > radius then continue end
		table.insert(players, player)
	end
	return players
end

-- get and print the closest player to 0, 0, 0
local player, magnitude = GetClosestCharacter(Vector3.new(0, 0, 0))
print(player, magnitude)

-- get and print the closest player to electricarea
local player, magnitude = GetClosestCharacter(electricarea.Position)
print(player, magnitude)

-- get table of all players within 50 studs of electricarea
local players = GetCharactersWithin(electricarea.Position, 50)
print(players)
1 Like