Checkpoints work just fine in Studio, but has an issue in Player

I’m working on a checkpoint system for my game which seems to be going well, as it works in studio with no issues whatsoever. However, when I go to test the system with friends, it has a tendency to (at random) send us back to where the start of the level is.

Now all you need to do is reset your character to go back to the checkpoint, but I’d rather that not be the case for two reasons:

  • The player might find it confusing/ frustrating and just leave
  • The game is speed based, so having to reset your character (sometimes multiple times) slows you down way more than it’s supposed to.

I figure maybe there is something faulty about what I currently have. But I can’t think of what it could be. :confused: Any help will be greatly appreciated.

local spawn = script.Parent
spawn.Touched:connect(function(hit)
	if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
		local player = game.Players:GetPlayerFromCharacter(hit.Parent)
		local checkpointData = game.ServerStorage:FindFirstChild("CheckpointData")
		if not checkpointData then
			checkpointData = Instance.new("Model", game.ServerStorage)
			checkpointData.Name = "CheckpointData"
		end
		
		local checkpoint = checkpointData:FindFirstChild(tostring(player.userId))
		if not checkpoint then
			checkpoint = Instance.new("ObjectValue", checkpointData)
			checkpoint.Name = tostring(player.userId)
			
			player.CharacterAdded:connect(function(character)
				wait()
				character:WaitForChild("HumanoidRootPart").CFrame = game.ServerStorage.CheckpointData[tostring(player.userId)].Value.CFrame + Vector3.new(0, 4, 0)
			end)
		end
		
		checkpoint.Value = spawn
	end
end)
5 Likes

You should set the Player.RespawnLocation property to the spawn location instead of doing what you’re doing.

Is it possible to do that multiple times? There’s usually like 4~7 checkpoints in a level

[edit: now that I think about it there’s also the fact that players can be at different parts of the level, I don’t want anyone to be able to skip because someone else got there first]

When you say start of the level, you mean to the last spawn you touched? Also, RespawnLocation is a property of the Player so each Player could have a unique RespawnLocation.

when i say the start of the level i mean like the original spawn location.

But if that’s the case, I can try to give it a shot :0

Try this code – it will allow you to use just 1 single script instead of several.

local checkpointData = game.ServerStorage:FindFirstChild("CheckpointData")
if not checkpointData then
	checkpointData = Instance.new("Model", game.ServerStorage)
	checkpointData.Name = "CheckpointData"
end

for i,v in ipairs(workspace.Checkpoints:GetChildren()) do
	v.Touched:Connect(function(hit)
		if hit and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
			local player = game.Players:GetPlayerFromCharacter(hit.Parent)

			local checkpoint = checkpointData:FindFirstChild(tostring(player.userId))
			if not checkpoint then
				checkpoint = Instance.new("ObjectValue", checkpointData)
				checkpoint.Name = tostring(player.userId)

				player.CharacterAdded:connect(function(character)
					wait()
					character:WaitForChild("HumanoidRootPart").CFrame = checkpointData[tostring(player.userId)].Value.CFrame + Vector3.new(0, 4, 0)
				end)
			end

			checkpoint.Value = v
		end
	end)
end

You’d have to group all the spawns in a folder or model in workspace called Checkpoints but this will be better than having individual scripts in each checkpoint

This code would cause a memory leak. (Just use the RespawnLocation property instead)

It’s also possible the parts aren’t capturing the Touched event sometimes — try making them CanCollide false for better hit detection.

Aah… I’m rather tired and not seeing it, where exactly?

It’s a property you set on per player. Here’s an example:

local Players = game:GetService("Players")

local spawn = script.Parent
spawn.Touched:Connect(function(hit)
    local Humanoid = hit.Parent:FindFirstChild("Humanoid")
    if Humanoid then
        local Player = Players:GetPlayerFromCharacter(Humanoid.Parent)
        if Player then
            Player.RespawnLocation = spawn
        end
    end
end)

(I haven’t tested this code so it might not work but it should give you an idea on how to script it at least)

I meant where was the memory leak?

The checkpoint (ObjectValue) was never destroyed after the player left.

Aah, yes. Thanks for pointing that out. :slight_smile:

With all due respect though, this was just for capturing touched checkpoints — not handling player leaving which would include cleaning up any instances created for the player. :slight_smile:

Parenting the ObjectValue to the player or just setting the RespawnLocation would be better and wouldn’t require any manual cleaning up.

Yup, I agree with RespawnLocation — I was just taking what he already written and streamlining it a bit.

My bad, I didn’t know that you’d gave a suggestion I didn’t get the notifs for some reason ;-;

I’ll definitely give it a shot though, as luckily enough I already thought to store the checkpoints into a folder

it still has the same error, though i will admit it is much more organized than mine

I tried to use player.respawnposition earlier but it seems to only work with “spawnlocation” parts and not normal parts

(I worry about using spawn locations as I don’t really want the player to spawn anywhere else if they just entered the level)

No worries :slight_smile: So could you provide more info on what exactly happens? If you try touching the first checkpoint and reset, does it reset you at that checkpoint? Try this for a few of the checkpoints and see if it always brings you to the beginning.