Parts not destroying?

Hey, devs!

Sorry that this post is long, but…

The last week or two, I have been developing an “assist mode” for players who want it. One of the features is to use PathfindingService to create a path, then create parts on every waypoint to draw to the location specified. Everything works fine up until destroying the old waypoints.

The idea is when you are moving, delete old parts, generate new parts to the end of the map or whatever other location on every waypoint, and that’s it. Like I said, it all works, but old parts don’t destroy.

Here is a screenshot of what happens:

And as you could imagine, it generates so many parts until studio just freezes or crashes.

What it does is when it generates the path and parts, it puts the parts into a table that gets returned to the script calling the function. I use a for loop to loop through them all and destroy them.

I have tried using :Remove() instead of :Destroy(), I’ve tried setting the parent of the part to nil manually instead of :Remove() and :Destroy(), when I print the table, all of the parts are in the table, when I print the part itself, it prints the name of the part (like you would expect), when I print typeof(Part), it prints “Instance,” I created a function built into a system to clear every part with the name “WaypointPart” and called that right before the new parts generate (all that does is make it so the parts don’t generate until after the player stops moving), and nothing has worked.

Here is the code relevant to this:

Main server script:

local runService = game:GetService("RunService")

local previousWaypoints

runService.Heartbeat:Connect(function()
	if assistMode.IsEnabled(player) then
		if character.Humanoid.MoveDirection.Magnitude > 0 then
			if assistMode.PriorityPart then
				if previousWaypoints then
					for _, previousWaypoint in previousWaypoints do
						previousWaypoint:Destroy()
					end
				end

				previousWaypoints = assistMode:DrawPathToPriority()
			end
		end
	end
end)

The Assist Mode module:

local pathfindingService = game:GetService("PathfindingService")

local module = {}
module.PriorityPart = workspace:WaitForChild("TestPart")

function module:DrawPathToPriority()
	local path = module.CreatePathToEnd()
	
	local waypointParts = {}
	
	if path and path.Status ~= Enum.PathStatus.NoPath then
		for _, waypoint: PathWaypoint in path:GetWaypoints() do
			local a = create.WaypointPart(waypoint.Position)
			table.insert(waypointParts, a)
		end
	end
	
	return waypointParts
end

function module.CreatePathToEnd(): Path
	local path
	
	if module.PriorityPart then
		path = pathfindingService:FindPathAsync(Players:GetPlayers()[1].Character.HumanoidRootPart.Position, module.PriorityPart.Position)
	end
	
	return path
end

return module

And the CreateInstance module:

function module.WaypointPart(position: Vector3)
	local newPart = Instance.new("Part")
	newPart.Name = "WaypointPart"
	newPart.Size = Vector3.new(0.4, 0.4, 0.4)
	newPart.Anchored = true
	newPart.CanCollide = false
	newPart.Transparency = 0.5
	newPart.Material = Enum.Material.Neon
	newPart.BrickColor = BrickColor.new("Bright yellow")
	newPart.Shape = Enum.PartType.Ball
	newPart.Position = position - Vector3.new(0, 0.45, 0)
	newPart.Parent = workspace.FX
	
	return newPart
end

Any and all help is appreciated. Thank you!

Best regards,
Amora

4 Likes

Only one thing I can really think of here, might sound dumb but maybe you forgot about adding a pairs to the for loop inside of the Main server script?

local runService = game:GetService("RunService")

runService.Heartbeat:Connect(function()
	if assistMode.IsEnabled(player) then
		if character.Humanoid.MoveDirection.Magnitude > 0 then
			if assistMode.PriorityPart then
				if previousWaypoints then
					for _, previousWaypoint in pairs(previousWaypoints) do
						previousWaypoint:Destroy()
					end
				end

				previousWaypoints = assistMode:DrawPathToPriority()
			end
		end
	end
end)

Nope. It works the exact same either way.

1 Like

Maybe use the debris service? Debris:AddItem(previousWaypoint, 2)

1 Like

If the previousWaypoints = assistMode:DrawPathToPriority() line runs then a stupid idea that might work is defining previousWaypoints before the Heartbeat function:

local previousWaypoints
runService.Heartbeat:Connect(function()
	...

That is how it is done already. I just didn’t include that line with the script in the post

1 Like

I thought of that, but I don’t want old parts to stay while still moving. It is a good idea if they sat still for a couple seconds, but the game is going to be almost all parkour, so they’ll be constantly moving

1 Like

Can you add a print(previousWaypoint) above the Destroy() line to see if that loop runs at all?

I did, and I mentioned in the original topic that it just prints the name like you would expect, which is “WaypointPart”

Have you verified it’s not a client-server issue? I’m asking because this bug seems weird to me.

Also does the console show any errors at all?

I haven’t, and I don’t know exactly how I would. I can try when I get home, though.

If the parts aren’t showing when you test from a player perspective it is, if they’re still showing it’s not.

By player perspective I mean not the server mode with the free camera movement.

Also, another wild scenario is that another script caches and brings back the parts.

Well, I guess I have done that. It still shows on both the server and from player perspective. I’m just hoping it isn’t caching them and bringing them back. I have literally no idea how I would fix that :sob:

Try pressing Ctrl + Shift + F while in studio, a window will pop up, type .Destroying in there and see if any script comes up.

Also if they’re being cached they’re 100% being cloned before that, so search for :Clone() if the above doesn’t work.

Actually not 100% there’s a slight chance the caching script is instancing new objects and looping through all their properties to copy from one to the other, but common how unlucky can you be.

I never got the notification on this… sorry.

I also always forget about that little window. Nothing shows up inside of it, either. And when I search :Clone(), neither of the scripts show up.


I also tried adding a .Destroying connection right after destroy gets called in the for loop, all it does is print “Destroying”, and it does just that, but the parts never destroy.

I also print the previousWaypoint before it gets destroyed like I initially tried before creating the topic, but I also added a print after it gets destroyed, and I print it five seconds after that. All three times it prints, it just prints “WaypointPart”, which is the name of the part. Also very strangely, after the five seconds in the for loop, the individual part that the loop is on destroys??? And it does the same when I shorten the time, but only the very first set of waypoint parts. Any others after don’t do that.

The parts only destroy when a wait is added, even a blank wait (task.wait()) will destroy them, but it is only the very first set. No others do.

This may be the solution actually, I have noticed certain Roblox functions require yielding to function properly. Most of the time I needed it a simple task.wait() fixed the issue.

I wish it would be the full solution, however, not sure if I explained it well enough, so here is a video of what happens:

I had to compress it to upload it here. Don’t mention the terrible quality lol

try to clear all children of the workspace.FX using clearallchildren

if previousWaypoints then
    for _, previousWaypoint in pairs(previousWaypoints) do
        previousWaypoint:ClearAllChildren()
    end

    local remainingChildren = workspace.FX:GetChildren()
    for _, child in pairs(remainingChildren) do
        print("Remaining child:", child.Name)
    end
end

and print it to be sure it got deleted, if it doesn’t it will print the part that don’t

Just does the same weird effect I get with almost every other thing I’ve tried. It doesn’t even let the parts appear until I stop moving because they are all getting destroyed immediately when I am, giving no time to see it appear.

then add a

task.wait(0.5)

before the

previousWaypooint:ClearAllChildren()