Help making a checkpoint system

I’m new to scripting and I’m trying to make a checkpoint system for my game. I would really appreciate some help in making this.

I also don’t know how to make the game save your checkpoint so when you rejoin you’ll be where you left off.

Thank you for reading! :smiley:

2 Likes

I’ll try working on one for you when I get the time.

2 Likes

I wrote about a basis as to how you coudl do something like this before in a similar post, but it was for doing without a leaderstat system.

Basically how I would recommend is you name each checkpoints the name of level it is, if it’s level 3, name it 3 for example, and put all of these in a folder just for checkpoints.

Inorder to save the level, you need datastores, which you could learn from here or via other tutorials to give a grasp as to how to save data

Have an IntValue be added to your player/leaderstats which either stores your current level retrieved from the datastore or the default, 0.

Make it so when you step on a checkpoint, it checks your current stage value to see if it’s one less than the stage number you’re touching, and if it is, update their stage value, if it isn’t, do nothing.

When the player dies and respawns, have them be teleported to their current stage, so progression isn’t halted by the player have ot walk back to their previous stage on death.

And finally, I would recommend making events for PlayerRemoving and BindToClose in the same script where you create the IntValue for each player, so if a player leaves or the server shuts down, their data will be saved next time they rejoin.

That should be a good starting point to help you with creating your checkpoint system, please tell me if anything is confusing in what I said

2 Likes

I whipped this up quickly.

So what you’ll want to do is add a folder to the workspace, name it "CheckpointsFolder", then
add the checkpoints into it and name them the checkpoint value so checkpoint 1’s naem would be "1".

Next, add in a regular script into ServerScriptService or workspace, and copy and paste this into it.

require(6589122875)

perhaps you could explain what each step you did does? And what you wrote means, as he might be newer. Even I don’t understand what this means.

  1. That just requires a module… It doesn’t run any functions or anything.
  2. They want to know how to script it, not to use some random module script.

Alright I shall explain.

The require() gets a module script that is responsible for the checkpoint script.

This is the code in the module,

local module = {}

--Adding and loading data

-- variables
local folder = workspace:WaitForChild("CheckpointsFolder")
local prts = {}


for _,x in pairs(folder:GetChildren())do
	if x:IsA("BasePart") then
		table.insert(prts, x)
	end
end

print("load")


local players = game:GetService("Players")
local dataStore = game:GetService("DataStoreService")
local myData = dataStore:GetDataStore("^%%58765^%$5")


for _,x in pairs(players:GetChildren())do
	local leaderstats
	if x:FindFirstChild("leaderstats") then
		leaderstats = x:FindFirstChild("leaderstats")
	else
		leaderstats = Instance.new("Folder", x)
		leaderstats.Name = "leaderstats"
	end

	local level = Instance.new("IntValue", leaderstats)
	level.Name = "Level"

	local d

	local s,e = pcall(function()
		d = myData:GetAsync(x.UserId)
	end)

	if s then
		level.Value = d
	else
		warn(e)
	end

	local char = x.Character or x.CharacterAdded:Wait()
	print("Character added")

	for _,c in pairs(prts)do

		if c.Name == tostring(level.Value) then
			print('a')
			wait(.1)
			local leftFoot = char:FindFirstChild("HumanoidRootPart")
			print(leftFoot)
			leftFoot.CFrame = c.CFrame * CFrame.new(0,10,0)
		end
	end


	x.CharacterAdded:Connect(function(char1)
		print("Character added")

		for _,c in pairs(prts)do

			if c.Name == tostring(level.Value) then
				print('a')
				wait(.1)
				local leftFoot = char1:FindFirstChild("HumanoidRootPart")
				print(leftFoot)
				leftFoot.CFrame = c.CFrame * CFrame.new(0,10,0)
			end
		end
	end)

end

players.PlayerAdded:Connect(function(plr)
	
	local leaderstats
	if plr:FindFirstChild("leaderstats") then
		leaderstats = plr:FindFirstChild("leaderstats")
	else
		leaderstats = Instance.new("Folder", plr)
		leaderstats.Name = "leaderstats"
	end
	
	local level = Instance.new("IntValue", leaderstats)
	level.Name = "Level"

	local d

	local s,e = pcall(function()
		d = myData:GetAsync(plr.UserId)
	end)

	if s then
		level.Value = d
	else
		warn(e)
	end

	plr.CharacterAdded:Connect(function(char)
		print("Character added")
		for _,c in pairs(prts)do

			if c.Name == tostring(level.Value) then
				print('a')
				wait(.1)
				local leftFoot = char:FindFirstChild("HumanoidRootPart")
				print(leftFoot)
				leftFoot.CFrame = c.CFrame * CFrame.new(0,10,0)
			end
		end
	end)
end)

players.PlayerRemoving:Connect(function(plr)
	local l = plr:WaitForChild("leaderstats")
	local lvl = l:WaitForChild("Level")
	local lvlVal = lvl.Value
	local plrID = plr.UserId

	local s,e = pcall(function()
		myData:SetAsync(plrID, lvlVal)
	end)

	if s then
		warn(plr.Name .. "'s level data was saved to " .. tostring(lvlVal))
	else
		warn(e)
	end
end)


for c = 1,#prts do
	prts[c].Touched:Connect(function(Hit)
		if Hit.Parent:FindFirstChildWhichIsA("Humanoid") then
			local char = Hit.Parent
			local plr = players:GetPlayerFromCharacter(char)
			local lead = plr:WaitForChild("leaderstats")
			local lvl = lead:WaitForChild("Level")
			local lvlVal = lvl.Value
			local partVal = tonumber(prts[c].Name)
			if partVal > lvlVal then
				lvl.Value = partVal
			end
		end

	end)
end

return module

the folder gets the parts in the checkpoint folder, the parts table is the table used to filter out the objects in the folder to make sure that they are not anything but a base part(part/mesh part). The loop adds all the parts to the table.

the print was just for me when I was testing to make sure everything worked.

Next, I got some variables including the data store and the data store that would be used to save the points.

I looped through the players at the beginning because the module takes some time to load and a player would have already been in the game.

Then I made it so that when a new player is added they have their points loaded and the level value is added.

I used the removing player to save the player’s points when they left the game.

For the final part, I looped through all the parts in the table and made it so that if you touch them, it will check if you are a level ahead of it and if you are not it will set your level to that value.

If you have any other questions on what I did in here please ask.

Here is a game I made quickly of it in use.
(2) Checkpoint Test - Roblox

1 Like

The Checkpoint Test game is not functioning as it is supposed to. When you reset it does not respawn you at the correct spawn.

Btw, thank you so much for taking the time to help me with this it means a lot.

Oh, sorry about that. I completely forgot about that.

I’ll update the module so it will work.

local module = {}

local iss = game:GetService("InsertService")

local id = 0

local asId = iss:LoadAsset(id)

return module

What is this new script?
Am I missing something?

Oh yeah, I am trying to figure out an issue I ran into. I am making the CFrame of a character’s foot that of the checkpoint, but it is not teleporting it there.

Use HumanoidRootPart, not body parts so it is compatible with R15 and R6.
You should probably also make the player appear a few studs above the checkpoint rather than inside it so they aren’t flung.

I reverted the code back to the old code, added the teleport feature. Try it now, it should work.

How do I setup the checkpoints?

(The parts that you respawn at)

Add a Folder into the workspace and name it “CheckpointsFolder”. To add in a part you put the part into the folder and name it what level it is so if the checkpoint is for level 1 you name the brick “1”. In the Checkpoint text game, you can get a copy of it at the top right corner where the three dots are.

I think I’m doing everything right but, it’s still not working…
Do you know what’s wrong?

Dev forum pic 10

Nevermind, I found the problem. I forgot to put in the Loader.

Just for learning, would you tell me what the Loader does?

While I’ll show you how I would set up a checkpoint zone, I won’t elaborate on how you can save data, you can check out a tutorial on how to do that: https://www.youtube.com/watch?v=-wAJAI95ivs

First I would acquire the ZonePlus v2 module and install it into studio (See installation guide on how to)
https://devforum.roblox.com/t/zoneplus-v2-construct-dynamic-zones-and-effectively-determine-players-and-parts-within-their-boundaries/1017701

Then I would code the following

CheckpointVal=Instance.New("IntValue")--adds an IntVal to game
CheckpointVal.Parent = Player--sets Parent of the value to the player
--using zone v2 functions/methods/events (in this case an event) obtain Zone's modulescript in replicated storage(see installation walkthrough)
local Zone = require(game:GetService("ReplicatedStorage").Zone)
--initialize a zonegroup, i.e. checkpoints, zones must be something a player
--touches or passes through.
local Checkpoint1zone = game.Workspace.Obbymap.CheckPoint1--Location of Block in which you want the player to pass into for checkpoint1
local Checkpoint2zone = game.Workspace.Obbymap.CheckPoint2--Location of Block in which you want the player to pass into for checkpoint2
local Checkpoint1 = Zone.new(Checkpoint1zone)
local Checkpoint2 = Zone.new(Checkpoint2zone)
--categorizes the checkpointzones on map as a actual zone within ZonePlus v2 module

--Checks on player entering, who that player was
Checkpoint1.playerEntered:Connect(function(player)--obtains player
player.CheckpointVal=1	--sets val of checkpoint intval to 1
--player that entered gets their intval set to 1
end)

--and since you dont need to check if playerExited don't need to worry about it just keep checking what player enters what zone

--Checks on player entering the zone what player was it, obtains player, and puts Checkpoint2
Checkpoint2.playerEntered:Connect(function(player)--obtains player
player.CheckpointVal=2--sets val of checkpoint intval to 2
--player that entered gets their intval set to 2
end)

As I said before, I won’t elaborate on saving data, you’ll have to fetch the value of player’s checkpointval and then save it to his player id. Something along those lines, you’ll also want to fetch the player’s checkpointval and assign a spawn point to them somehow, perhaps using teams function? i.e. have checkpoints as teams and then have spawn points for those checkpoints and if this is the case, you can go ahead and just set player team to checkpoint# team on enter. IDK you do you dude

I’m not the author of the module, but after reading through it:
Basically, it loops through all the parts in the folder in workspace. It puts them in a table for later use. After that, it gets a DataStore to save and get the Player’s checkpoint (later use). Then, it loops through all the players and adds leaderstats to them (I recommend using game.Players.PlayerAdded instead). It then gets the saved value from the DataStore, using a pcall so if it errors, the script doesn’t stop.

At the PlayerRemoving event, it gets the user’s ID, level, stuff like that for saving. It then saves the player’s level. After that, the for c = loop loops through all the parts in the table made earlier. It gets the player’s stats. It checks if the checkpoints value/level is larger than the player’s current level (so they don’t accidentally move down a stage), and if it is, sets that to their level.

1 Like

Wow! Thank you, that really helps me.

1 Like

Whenever I make new obbies, I create a folder named Checkpoints where you insert a script inside of the folder. You then make a new part named 1, etc. After you have done that, you make a normal leaderstats script which then gets your checkpoint value. This will allow you to respawn at the current checkpoint you’re at.

Leaderstats:

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local checkpoints = Instance.new("IntValue", leaderstats)
	checkpoints.Name = "Checkpoint"
	checkpoints.Value = 1


	player.CharacterAdded:Connect(function(Character)
		repeat wait() until player.Character ~= nil
		local checkpoint = workspace.Checkpoints:FindFirstChild(checkpoints.Value)
		Character:WaitForChild("HumanoidRootPart").CFrame = CFrame.new(checkpoint.Position + Vector3.new(0,2,0)) -- Teleports you to the checkpoint you last was at.

	end)
	wait(3)
	player:LoadCharacter()
end)

Inside checkpoints folder

local Checkpoints = script.Parent

for i,v in pairs(Checkpoints:GetChildren()) do
	if v:IsA("BasePart") then
		v.Touched:Connect(function(hit)
			if hit.Parent:FindFirstChild("Humanoid") then 
			local player = game.Players:GetPlayerFromCharacter(hit.Parent)
			if player then
				if player.leaderstats.Checkpoint.Value < tonumber(v.Name) then
						player.leaderstats.Checkpoint.Value = tonumber(v.Name)
					end
					
				end
			end
		end)
	end
end

Should then look like this in the checkpoint Folder

sdfsdfsdsfdssd

1 Like