Frost's Stage Skip System

Frost's Stage Skip System

Frost’s Stage Skip System

Frost's Stage Skip System

Frost's Stage Skip System

Frost's Stage Skip System

The following resource is a stage skip system that is compatible with both R15 & R6 avatars.

Basically, there is a TextButton. When the TextButton is clicked on by the player, they are prompted with a developer product. When the product is purchased, the player is skipped to the next stage. The TextButton comes with a click sound effect that plays when the TextButton is clicked on. The TextButton becomes visible when the player reaches the first stage and becomes invisible when the player reaches the end of the experience/obstacle course. If the player decides to play again after finishing, don’t worry, the TextButton will become visible again when they reach a stage to replay.

It was something I needed for a simple experience that I’m working on, and I ventured out to the ToolBox and YouTube in hopes of finding something to satisfy my need but all I came across were the same systems that are only compatible with R6 as well as outdated, no longer functioning systems. I was frustrated that I couldn’t find such a simple thing. So, I decided to create what I need myself using the Roblox Assistant, ChatGPT, my brain and a little help from #help-and-feedback:scripting-support .

This system can be used in a number of applications, such as:

  • Obbies
  • Guess the logo experiences (which is what I needed the system for)

Other applications don’t come to my mind.

Frost's Stage Skip System

Frost's Stage Skip System

Here are the instructions you need to follow in order to use my skip stage system:

  1. Ungroup the model. Place the ScreenGui in StarterGUI and place the empty StageStarts folder in Workspace. And delete the part titled DELETEME.

  2. Now, at the beginning of each stage, create a Part. You have to do this for the first stage as well. Make sure the parts all have different names. They will be the parts the player is teleported to (excluding the part for stage 1).

To prevent the Roblox avatar from falling through the part it is teleported to, I have made it teleport 10 studs above the part it is teleported to. So, it should already be fail safe but if you want to do more to be extra sure nothing goes wrong, you can adjust the offset variable in the TextButton’s Configuration script or make the parts the player is teleported to thick and/or put another part underneath the part the player is teleported to.

  1. Place all of the parts that you have created, which the player will be teleported to, into the StageStarts folder (do not put fail safe parts into the folder if you decided to create such parts as extra).

  2. Place a part belonging to the end area of the obstacle course into the StageStarts folder. Likewise, place a part belonging to the spawn area of the obstacle course into the StageStarts folder. They should not belong to stages. Ensure that they are uniquely named as well.

  3. Create a developer product. And copy its assetID. Open up the ScreenGui then TextButton then Configuration. We will change the local productID line (line 6). Change the 0’s to the assetID you copied.

  4. In the same script, we will change the local starts line (line 8). In the curly brackets, for each part in the StageStarts folder, add game.Workspace:WaitForChild("StageStarts"):WaitForChild("PARTNAMEHERE"), but LIST THEM IN ORDER or else this resource won’t work as intended and of course, change “PARTNAMEHERE” to the name of the part. Also, at the end, add game.Workspace:WaitForChild(“StageStarts”):WaitForChild(“PARTNAMEHERE”`) for the part belonging to the end area of the obstacle course. Do not add for the part belonging to the spawn area of the obstacle course, anywhere in the line.

  5. Open up ScreenGui then TextButton then Visibility. We will change the local FirstStageStart line (line 1). Where it says “FIRSTPARTNAME”, change it to the name of the part belonging to the first stage that you had put inside of the StageStarts folder.

  6. In the same script, we will change the local EndPlatform line (line 2) as well. Where it says “ENDPARTNAMEHERE”, change it to the name of the part belonging to the end area of your obstacle course that you had put inside of the StageStarts folder.

  7. In the same script, we will change the local SpawnPlatform line (line 3) as well. Where it says “SPAWNAREAPARTNAMEHERE”, change it to the name of the part you had put inside of the StageStarts folder that belongs to the beginning of the obstacle course (before stage 1).

  8. In the same script, we will change the 25th line beginning with "if v:". Change the “FIRSTPARTNAME” to the name of the part belonging to the first stage that you had put inside of the StageStarts folder and on the same line, change “ENDPARTNAMEHERE” to the name of the part belonging to the end of your obstacle course that you had put inside of the StageStarts folder.

After that, you should be all set, enjoy!

Frost's Stage Skip System

Frost's Stage Skip System

Here is a demonstration video demonstrating different cases using an R15 avatar, AFAIK the result does not change in R6:

In all 3 cases, you will notice that the spawn area and end/winners area causes the button to become invisible, that is intended behavior, GOOD behavior! Because, think about it, where will you skip to if you are at the winners area and what’s the purpose of skipping to stage 1 from spawn?!

Also, here’s how it turned out in the logo guessing experience I was working on, I love it:

It turned out as I intended.

Frost's Stage Skip System

Frost's Stage Skip System

  1. I used a TextButton, you can use an ImageButton, it really doesn’t matter. If you use an ImageButton, just be sure to put the Configuration and Visibility localscripts inside of it. Feel free to use the icon below for your ImageButton.

  1. Open Source Demonstration Place: Frost’s Stage Skip System Demonstration Place - Roblox. Taking a look at it on Studio can help you better understand how my system works.
    Frost's Stage Skip System

Frost's Stage Skip System

If you for some reason experience an issue with this system, replace the script content with these:

Configuration LocalScript for Debugging
local TextButton = script.Parent
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local productId = 0000000000 -- Change the zeros to the developer product ID. 
local Sound = script.Sound 
local starts = {game.Workspace:WaitForChild("StageStarts"):WaitForChild("PARTNAMEHERE")} -- Change PARTNAMHERE to the part name belonging to the first stage, add game.Workspace:WaitForChild("StageStarts"):WaitForChild("PARTNAMEHERE") as much as you need, seperate them with commas and do not add a comma after the last one!
local currentstart = 1 -- Do not touch unelss you know what you are doing. 
local offset = Vector3.new(0, 10, 0) -- How high above the part the player will be teleported to, increase 10 or decrease 10 as you please.

local function handlePurchaseFinished(playerID, productId, wasPurchased)
	print("Purchase finished event fired")
	if wasPurchased  then
		character:PivotTo(CFrame.new(starts[currentstart+1].Position +offset))
		currentstart = currentstart + 1 
		print("Product purchased, teleported player")
	else
		print("Product not purchased, did not teleport player")
	end
end

local function onClick()
	MarketplaceService:PromptProductPurchase(player, productId)
	Sound:Play()
	print("Prompted purchase for product with ID:", productId)
end

local function onDoorTouched(door)
	for i, d in ipairs(starts) do
		if d == door then
			currentstart = i
			break
		end
	end
end

for _, door in ipairs(starts) do
	door.Touched:Connect(function(hit)
		local character = hit.Parent
		if character:IsA("Model") and character:FindFirstChild("Humanoid") then
			onDoorTouched(door)
		end
	end)
end

MarketplaceService.PromptProductPurchaseFinished:Connect(function(playerID,productId, wasPurchased)
	handlePurchaseFinished(playerID,productId, wasPurchased)
end)

TextButton.Activated:Connect(onClick)

Only do Visibility if you are certain the issue does not root from the Configuration Localscript, because you’ll be bombarded by print statements as a result of touch functions.

Visibility LocalScript for Debugging
local FirstStageStart = game.Workspace:WaitForChild("StageStarts"):WaitForChild("FIRSTPARTNAME") -- Name of a part in the first stage.
local EndPlatform = game.Workspace:WaitForChild("StageStarts"):WaitForChild("ENDPARTNAMEHERE") -- Name of a part in the end area. 
local SpawnPlatform = game.Workspace:WaitForChild("StageStarts"):WaitForChild("SPAWNAREAPARTNAMEHERE") -- Name of a part in the spawn area, not the first stage.
local Other = game.Workspace:WaitForChild("StageStarts"):GetChildren()
local gui = script.Parent
FirstStageStart.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") and hit.Parent == game.Players.LocalPlayer.Character then
		gui.Visible = true
		print("Player touched first stage so button is visible.")
	end
end)

EndPlatform.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") and hit.Parent == game.Players.LocalPlayer.Character then
		gui.Visible = false
		print("Player touched the end area so button is invisible.")
	end
end)

SpawnPlatform.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") and hit.Parent == game.Players.LocalPlayer.Character then
		gui.Visible = false
     print("Player touched a part from spawn area so button is invisible.")
	end
end)

for i,v in pairs(Other) do
	if v:IsA("Part") and not v:FindFirstChild("ENDPARTNAMEHERE") and not v:FindFirstChild("FIRSTPARTNAME")  then -- Do the same name changes like before.
		v.Touched:Connect(function(hit)
			if hit.Parent:FindFirstChild("Humanoid") and hit.Parent == game.Players.LocalPlayer.Character then
				gui.Visible = true
				print("Player conditionally touched, button visible.")
			end
		end)
	end
	end

After doing that, test the experience in Studio, and write /console into the chat, it’ll open the console (that black menu) and send me screenshots of everything that the script prints (printed text will be in white) on the console. It’ll help me understand which part of the script is failing. If you see any errors (red text) or warnings (yellow text) on the console, feel free to send them as well. I’ll do my best to address the issue. If the system needs updating, I’ll work on a rework.

Frost's Stage Skip System

Lastly, before signing off, I would like to make a few honorable mentions:

@toasterman1 for their emphasis on the importance of using PivotTo()
@OneXZero_DEV and @fraiseFR004 for their assistance regarding developer product purchase checking
@gara7722 for their assistance regarding stage checking

Without them, I wouldn’t have been able to make this resource.
Frost's Stage Skip System

If you have constructive feedback or basically believe that the code can be written more efficiently, feel free to share your feedback in the topic replies section. I am a beginner programmer, so I am open to learning more. If I agree, I will edit my system to implement your suggestions and credit you.

6 Likes

This is great! I love the system and it is really easy to use!

I do have a question, however.

Case 1 & Case 2: Both of these cases seem to work the same. Case 1 just showcases skipping EVERY stage, where Case 2 showcases only skipping a couple of them and playing the rest. It is pretty standard to assume that if you can skip a few stages you can skip ALL of them.

Other than that, this is a really great resource. (Basically I am saying that having both the Case 1 and Case 2 demonstrations are redundant. I would just pick Case 2. It is up to you though what you want to do.)

1 Like

True, true. I don’t know what to say, I just have a habit of checking everything in case something goes wrong. :rofl: :sob:

Maybe, a non-programmer can wonder if skipping everything would work, so I’ll just still keep them 2.

I understand what you mean though and I just realized what you meant, and I do agree. However, I would prefer to keep them just to give users an impression that it is flawless.

Thanks for your kind words though, I appreciate it.

1 Like

No problem. Honestly, after reading what I replied with again, I would agree that it makes sense to keep both in as it is a valid question.

Overall, great system!

1 Like