How to detect closest part to Player using workspace:GetPartBoundsInRadius()?

Glad to see you’re back. Anyways, it seems to not play the sound for some reason? Also how would i make the player move toward the target part at the same speed no matter the distance, and how would i make it so that the player can’t hit the part again after having jumped off it until he hits another part or lands?

--|Targeting
local OnAir2 = false
local function Targeting()
    print("a")
    if Settings:GetAttribute("Moveset") == true and Settings:GetAttribute("Targeting") == false then
        print("c")
        local Params = OverlapParams.new()
        Params.FilterType = Enum.RaycastFilterType.Exclude
        Params.FilterDescendantsInstances = {Character}
        --------------------------------------
        local TargetPart = nil
        local Connection
        --------------------------------------
        Connection = UIS.InputBegan:Connect(function(Input)
            if Input.KeyCode == Enum.KeyCode.Space then
                if TargetPart then
                    Connection:Disconnect()
                    --------------------------------------
                    Settings:SetAttribute("Targeting", true)
                    --------------------------------------
                    Root.Anchored = true
                    --------------------------------------
                    Root.CFrame = CFrame.new(Root.Position, TargetPart.Position)
                    --------------------------------------
                    Anims.Target:Play(0, 30)
                    --------------------------------------
                    local Sound0 = Sounds.Player.TargetingSound:Clone()
                    Sound0.Parent = Root
                    Sound0:Play()
                    --------------------------------------
                    Debris:AddItem(Sound0, 1.25)
                    --------------------------------------
                    local Start = Root.CFrame
                    for i = 0.1, 1, 0.1 do
                        Root.CFrame = Start:Lerp(TargetPart.CFrame, i)
                        task.wait(0)
                    end
                    --------------------------------------
                    Settings:SetAttribute("Targeting", false)
                    --------------------------------------
                    Root.Anchored = false
                    --------------------------------------
                    Anims.Target:Stop()
                    --------------------------------------
                    Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
                    --------------------------------------
                    spawn(function()
                        Glow:Create(Color3.fromRGB(0, 255, 255), "All", 1)
                    end)
                    --------------------------------------
                    local Sound1 = Sounds.Player.TargetHitSound:Clone()
                    Sound1.Parent = Root
                    Sound1:Play()
                    --------------------------------------
                    Debris:AddItem(Sound1, 2.75)
                end
            end
        end)
        --------------------------------------
        repeat
            local Parts = workspace:GetPartBoundsInRadius(Root.Position, 30, Params) 
            print("a")
            --------------------------------------
            local MaxDistance = 9999
            local ClosestPart = nil

            for _, Part : Part in pairs(Parts) do
                local Magnitude = (Part.Position - Root.Position).Magnitude
                if Part:HasTag("Target") and Magnitude < MaxDistance then
                    MaxDistance = Magnitude
                    ClosestPart = Part
                end
            end
            --------------------------------------
            if ClosestPart then
               --[[ if TargetPart and not TargetPart.Target.Enabled then
                    local Sound = Sounds.Player.TargetSound:Clone()
                    Sound.Parent = TargetPart
                    Sound:Play()
                    --------------------------------------
                    Debris:AddItem(Sound, 0.5)
                    --------------------------------------
                    TargetPart.Target.Enabled = true
                end]]
                --------------------------------------
                ClosestPart.Target.Enabled = true
            end
            --------------------------------------
            if TargetPart and TargetPart ~= ClosestPart then
                TargetPart.Target.Enabled = false
            end
            --------------------------------------
            TargetPart = ClosestPart
            --------------------------------------
            task.wait()
        until Humanoid:GetState() ~= Enum.HumanoidStateType.Freefall and Humanoid:GetState() ~= Enum.HumanoidStateType.Jumping

        if TargetPart then
            TargetPart.Target.Enabled = false
        end
        --------------------------------------
        Connection:Disconnect()
    end
end

Hey bro, you still there? It’s been a 2 weeks i think

wow, I think it is very sad that nobody ended up responding. So I made this script for you, hopefully this is what you wanted, since I don’t fully understand your query:

local players = game:GetService "Players"
local contextActionService = game:GetService "ContextActionService"

local player = players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:FindFirstChildOfClass "Humanoid"

local billboardGui = player.PlayerGui:WaitForChild "BillboardGui"

local closestPart = nil
local closestDistance = nil

humanoid.StateChanged:Connect(function(old: Enum.HumanoidStateType, new: Enum.HumanoidStateType)  
	if new == Enum.HumanoidStateType.Jumping then--player just started jumping, so checking for any targets here
		local params = OverlapParams.new()
		params.FilterDescendantsInstances = {character}
		params.FilterType = Enum.RaycastFilterType.Exclude
		
		local targets = workspace:GetPartBoundsInRadius(character.PrimaryPart.Position, 15, params) :: {BasePart}
		
		for _, part in ipairs(targets) do
			if not part:HasTag "Target" then continue end
			if not closestPart then 
				closestPart = part
				closestDistance = player:DistanceFromCharacter(part.Position)
				continue 
			end

			local dist = player:DistanceFromCharacter(part.Position)
			if closestDistance <= dist then continue end
			
			closestPart = part
			closestDistance = dist
		end
		
		if not closestPart then return end--no closest part with target tag
		billboardGui.Adornee = closestPart
	elseif new == Enum.HumanoidStateType.Freefall and closestPart then--player is falling, connect the event, use the part acquired in the previous pass
		contextActionService:BindActionAtPriority("Teleport", function(_, state, obj) 
			if state ~= Enum.UserInputState.Begin then return Enum.ContextActionResult.Pass end
			character:PivotTo(closestPart.CFrame + Vector3.new(0, 2, 0))
			
			return Enum.ContextActionResult.Sink
		end, false, 10_000,Enum.KeyCode.Space)
	elseif old == Enum.HumanoidStateType.Freefall or new == Enum.HumanoidStateType.Landed then --just got back from falling, cleanup
		closestPart = nil
		closestDistance = nil
		billboardGui.Adornee = nil
		
		contextActionService:UnbindAction "Teleport"
	end
end)

here’s video of the script:


Hope this helps!

2 Likes

Hello, sorry for the late reply! Yes, it does indeed work, thank you, but there’s still a problem. If you start jumping when the ClosestPart isn’t within the 45 studs range, and then you move towards it while still falling/jumping, and it enters the range, the part will not be detected, as shown in this video.

I’m sorry, I went to bed, what exactly do you want to happen when the user jumps? Should all parts with tag Target get a billboard gui or only the closest?

The reason why none of these, even if you were to add a loop, update the billboardgui is because the humanoid jumping state actually lasts only like 0.5s, only for the initial force, but the rest is freefalling, it’s clear that you want the billboardgui to update when the user is freefalling, so instead, I switched the loop and the input binding’s spots, and now it works like you described:

local players = game:GetService "Players"
local contextActionService = game:GetService "ContextActionService"

local player = players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:FindFirstChildOfClass "Humanoid"

local billboardGui = player.PlayerGui:WaitForChild "BillboardGui"
local overlapParams = OverlapParams.new()

overlapParams.FilterDescendantsInstances = {character}
overlapParams.FilterType = Enum.RaycastFilterType.Exclude

local function getClosestTarget(): BasePart?
	local closestDistance = nil
	local closestPart = nil
	
	local targets = workspace:GetPartBoundsInRadius(character.PrimaryPart.Position, 15, overlapParams) :: {BasePart}

	for _, part in ipairs(targets) do
		if not part:HasTag "Target" then continue end
		if not closestPart then 
			closestPart = part
			closestDistance = player:DistanceFromCharacter(part.Position)
			continue 
		end
		
		local dist = player:DistanceFromCharacter(part.Position)
		if closestDistance <= dist then continue end

		closestPart = part
		closestDistance = dist
	end
	
	return closestPart
end

humanoid.StateChanged:Connect(function(old: Enum.HumanoidStateType, new: Enum.HumanoidStateType)  
	if new == Enum.HumanoidStateType.Jumping then
		contextActionService:BindActionAtPriority("Teleport", function(_, state, obj) 
			if state ~= Enum.UserInputState.Begin then return Enum.ContextActionResult.Pass end
			if humanoid:GetState() ~= Enum.HumanoidStateType.Freefall or not billboardGui.Adornee then return Enum.ContextActionResult.Pass end
			
			character:PivotTo(billboardGui.Adornee.CFrame + Vector3.new(0, 2, 0))
			return Enum.ContextActionResult.Sink
		end, false, 10_000,Enum.KeyCode.Space)
		
	elseif new == Enum.HumanoidStateType.Freefall then
		while humanoid:GetState() == Enum.HumanoidStateType.Freefall and task.wait() do
			billboardGui.Adornee = getClosestTarget()
		end
		
		billboardGui.Adornee = nil
		contextActionService:UnbindAction "Teleport"
	end
end)

also separation of concerns because why not. It’s nicer now.
anyway here’s video of script:

hope this helps!