PromptBase
PromptBase SelectGet Select
Close icon
General
Home
Marketplace
Create
Hire
Login
Chat
Sell
Explore

Prompt Details

Model
Chat - (gpt-6-astra)
Token size
1,738
Example input
[GAME IDEA, e.g. "an obby with moving platforms and a prize at the end"]: an obby with moving platforms, spinning bars and a golden trophy at the end [obby / tycoon / simulator / round-based minigame / other]: obby [never used Roblox Studio / made a few things / comfortable with Lua]: never used Roblox Studio [MUST-HAVES, e.g. "checkpoints, coin counter, leaderboard", or "none"]: heckpoints, a timer that shows how long the run took [SIZE: small, 5 minutes of play / medium, 15-30 minutes]: small, 5 minutes of play
Example output
Skybound Sprint: build plan and full scripts 1. The game in 3 lines - Play: Run, jump across floating platforms, dodge spinning bars, and survive tricky gaps. - Goal: Reach the golden trophy at the end of a short obstacle course. Checkpoints save your progress when you fall. - Core loop: Start the timer, clear obstacles, respawn at checkpoints when needed, finish the course, and try to beat your best time. This first version is designed for a beginner and takes about five minutes to play. The scripts build the obstacle course automatically, so you won't need to create dozens of platforms by hand. 2. Build this in Studio first You only need to create four objects by hand. The server script will build the platforms, checkpoints, spinning bars, moving platforms, finish area, and trophy. Step 1: Create the project 1. Open Roblox Studio and sign in. 2. On the start screen, click New and choose Baseplate. 3. If Explorer isn't visible, click View at the top, then click Explorer. Open Properties from the same menu if needed. 4. In Explorer, expand Workspace. Select the default SpawnLocation if there is one, and delete it using the Delete key. Keep the Baseplate for now; the script will remove it. Step 2: Create the objects In Explorer, right-click the indicated parent and choose Insert Object, or hover over the parent and click the + button. Search for the object type, then select it. 1. Workspace β†’ StartSpawn Type: SpawnLocation - Anchored: true - CanCollide: true - Transparency: 0 - Size: 12, 1, 12 - Position: 0, 4, 0 - Neutral: true 2. ServerScriptService β†’ ObbyServer Type: Script Leave the default script settings. This script builds the course and handles checkpoints, the timer, and wins. 3. StarterGui β†’ RunTimer Type: ScreenGui Set ResetOnSpawn to false. This keeps the timer visible when your character respawns. 4. RunTimer β†’ TimerClient Type: LocalScript The LocalScript will create the timer display automatically. What the finished Explorer tree looks like Workspace β”œβ”€β”€ Baseplate (Part) [removed by script] └── StartSpawn (SpawnLocation) ServerScriptService └── ObbyServer (Script) StarterGui └── RunTimer (ScreenGui) └── TimerClient (LocalScript) You do not need to make any other objects manually. The server script creates everything else during Play, including the leaderstats folder and its Wins value. 3. Scripts Create the scripts in the order below. For each one, double-click its name in Explorer, select all existing text in the editor, and replace it with the complete code. 1. ObbyServer Type: Script Put it in: ServerScriptService What it does: Builds the whole course and handles moving platforms, spinning hazards, checkpoints, run timing, deaths, and wins. The server controls all important game state. local Players = game:GetService("Players") local RunService = game:GetService("RunService") local startSpawn = workspace:WaitForChild("StartSpawn") local course = Instance.new("Folder") course.Name = "ObbyCourse" course.Parent = workspace local checkpoints = {} local touchDebounce = {} local finishDebounce = {} local movingPlatforms = {} local spinningBars = {} local PLATFORM_Y = 4 local PLATFORM_SIZE = Vector3.new(10, 1, 10) local COURSE_X = {0, 18, 36, 54, 72, 90, 108, 126, 144} -- Remove the default floor and any extra spawn locations. local baseplate = workspace:FindFirstChild("Baseplate") if baseplate then baseplate:Destroy() end for _, object in ipairs(workspace:GetDescendants()) do if object:IsA("SpawnLocation") and object ~= startSpawn then object:Destroy() end end startSpawn.Anchored = true startSpawn.CanCollide = true startSpawn.Size = PLATFORM_SIZE startSpawn.Position = Vector3.new(0, PLATFORM_Y, 0) startSpawn.Color = Color3.fromRGB(70, 200, 120) startSpawn.Neutral = true startSpawn.Duration = 0 local function makePart(name, size, position, color, parent) local part = Instance.new("Part") part.Name = name part.Size = size part.Position = position part.Anchored = true part.CanCollide = true part.Color = color part.Material = Enum.Material.SmoothPlastic part.TopSurface = Enum.SurfaceType.Smooth part.BottomSurface = Enum.SurfaceType.Smooth part.Parent = parent return part end local function makePlatform(x, color) return makePart( "Platform", PLATFORM_SIZE, Vector3.new(x, PLATFORM_Y, 0), color, course ) end local function getPlayerFromHit(hit) local character = hit:FindFirstAncestorOfClass("Model") if not character then return nil end return Players:GetPlayerFromCharacter(character) end local function setCheckpoint(player, position) checkpoints[player] = position player:SetAttribute("CheckpointPosition", position) end local function makeCheckpoint(x, number) local pad = makePart( "Checkpoint" .. number, Vector3.new(7, 0.35, 7), Vector3.new(x, PLATFORM_Y + 0.7, 0), Color3.fromRGB(0, 220, 255), course ) pad.Material = Enum.Material.Neon pad.Touched:Connect(function(hit) local player = getPlayerFromHit(hit) if not player or touchDebounce[player] then return end touchDebounce[player] = true setCheckpoint(player, Vector3.new(x, PLATFORM_Y + 4, 0)) player:SetAttribute("CheckpointMessage", "Checkpoint " .. number .. " saved!") task.spawn(function() task.wait(1) touchDebounce[player] = nil end) end) end local function makeMovingPlatform(x, number) local part = makePart( "MovingPlatform" .. number, Vector3.new(7, 1, 7), Vector3.new(x, PLATFORM_Y + 0.5, 0), Color3.fromRGB(255, 170, 0), course ) part.Material = Enum.Material.Metal table.insert(movingPlatforms, { part = part, basePosition = part.Position, phase = number * 1.7, distance = 5, speed = 1.2 }) end local function makeSpinningBar(x, number) local bar = makePart( "SpinningBar" .. number, Vector3.new(12, 0.8, 1), Vector3.new(x, PLATFORM_Y + 2, 0), Color3.fromRGB(255, 65, 65), course ) bar.Material = Enum.Material.Neon table.insert(spinningBars, { part = bar, x = x, angle = 0, speed = 1.8 }) end -- Build the fixed platforms. for _, x in ipairs(COURSE_X) do if x ~= 0 then makePlatform(x, Color3.fromRGB(95, 120, 190)) end end -- Moving platforms bridge the gaps between fixed platforms. makeMovingPlatform(27, 1) makeMovingPlatform(63, 2) makeMovingPlatform(99, 3) -- Checkpoints are normal Parts, not SpawnLocations. makeCheckpoint(54, 1) makeCheckpoint(108, 2) -- Spinning bars make three platforms more challenging. makeSpinningBar(36, 1) makeSpinningBar(90, 2) makeSpinningBar(126, 3) -- The finish platform and trophy. local trophy = makePart( "GoldenTrophy", Vector3.new(3, 4, 3), Vector3.new(144, PLATFORM_Y + 3, 0), Color3.fromRGB(255, 210, 0), course ) trophy.Shape = Enum.PartType.Ball trophy.Material = Enum.Material.Neon trophy.CanCollide = false local trophyTop = makePart( "TrophyTop", Vector3.new(4, 0.6, 4), Vector3.new(144, PLATFORM_Y + 5.2, 0), Color3.fromRGB(255, 230, 60), course ) trophyTop.Shape = Enum.PartType.Cylinder trophyTop.Material = Enum.Material.Metal trophyTop.CanCollide = false -- Falling below the course resets the character. local killZone = makePart( "KillZone", Vector3.new(400, 2, 100), Vector3.new(72, -20, 0), Color3.fromRGB(255, 0, 0), course ) killZone.Transparency = 1 killZone.CanCollide = false killZone.Touched:Connect(function(hit) local character = hit:FindFirstAncestorOfClass("Model") local humanoid = character and character:FindFirstChildOfClass("Humanoid") if humanoid then humanoid.Health = 0 end end) local function makeLeaderstats(player) local leaderstats = Instance.new("Folder") leaderstats.Name = "leaderstats" leaderstats.Parent = player local wins = Instance.new("IntValue") wins.Name = "Wins" wins.Value = 0 wins.Parent = leaderstats end local function resetRun(player) player:SetAttribute("RunActive", false) player:SetAttribute("RunFinished", false) player:SetAttribute("RunStartedAt", 0) player:SetAttribute("RunElapsed", 0) setCheckpoint(player, startSpawn.Position + Vector3.new(0, 4, 0)) if player.Character then player.Character:PivotTo(CFrame.new(checkpoints[player])) end end local function setupPlayer(player) makeLeaderstats(player) setCheckpoint(player, startSpawn.Position + Vector3.new(0, 4, 0)) player:SetAttribute("RunActive", false) player:SetAttribute("RunFinished", false) player:SetAttribute("RunStartedAt", 0) player:SetAttribute("RunElapsed", 0) player:SetAttribute("CheckpointMessage", "") player.CharacterAdded:Connect(function(character) local root = character:WaitForChild("HumanoidRootPart", 10) if not root or player.Parent ~= Players then return end local destination = checkpoints[player] or (startSpawn.Position + Vector3.new(0, 4, 0)) character:PivotTo(CFrame.new(destination)) local humanoid = character:WaitForChild("Humanoid", 10) if humanoid then humanoid.Died:Connect(function() -- The timer keeps running when the player dies. -- Respawning returns the player to their last checkpoint. end) end end) if player.Character then task.spawn(function() local root = player.Character:WaitForChild("HumanoidRootPart", 10) if root and player.Parent == Players then player.Character:PivotTo(CFrame.new(checkpoints[player])) end end) end end -- Start the timer when a player touches the start platform. startSpawn.Touched:Connect(function(hit) local player = getPlayerFromHit(hit) if not player or player:GetAttribute("RunActive") then return end if player:GetAttribute("RunFinished") then return end player:SetAttribute("RunStartedAt", workspace:GetServerTimeNow()) player:SetAttribute("RunElapsed", 0) player:SetAttribute("RunActive", true) end) trophy.Touched:Connect(function(hit) local player = getPlayerFromHit(hit) if not player or finishDebounce[player] then return end if not player:GetAttribute("RunActive") then return end finishDebounce[player] = true local startedAt = player:GetAttribute("RunStartedAt") or 0 local elapsed = math.max(0, workspace:GetServerTimeNow() - startedAt) player:SetAttribute("RunElapsed", elapsed) player:SetAttribute("RunActive", false) player:SetAttribute("RunFinished", true) local leaderstats = player:FindFirstChild("leaderstats") local wins = leaderstats and leaderstats:FindFirstChild("Wins") if wins then wins.Value += 1 end -- Give the player time to see their result, then allow another run. task.spawn(function() task.wait(5) if player.Parent == Players then resetRun(player) finishDebounce[player] = nil end end) end) Players.PlayerAdded:Connect(setupPlayer) Players.PlayerRemoving:Connect(function(player) checkpoints[player] = nil touchDebounce[player] = nil finishDebounce[player] = nil end) -- Handle players who joined before this script connected. for _, player in ipairs(Players:GetPlayers()) do if not player:FindFirstChild("leaderstats") then setupPlayer(player) end end -- Move platforms with matching assembly velocity so they can carry players. RunService.Heartbeat:Connect(function() local now = workspace:GetServerTimeNow() for _, data in ipairs(movingPlatforms) do local part = data.part local oldPosition = part.Position local offset = math.sin(now * data.speed + data.phase) * data.distance local newPosition = data.basePosition + Vector3.new(0, 0, offset) part.CFrame = CFrame.new(newPosition) part.AssemblyLinearVelocity = (newPosition - oldPosition) / math.max(1 / 240, 1 / 60) end for _, data in ipairs(spinningBars) do data.angle += data.speed / 60 data.part.CFrame = CFrame.new(data.x, PLATFORM_Y + 2, 0) * CFrame.Angles(0, data.angle, 0) end end) 2. TimerClient Type: LocalScript Put it in: StarterGui β†’ RunTimer What it does: Creates a timer at the top of the screen, shows checkpoint messages, and displays your finish time before the next attempt. local Players = game:GetService("Players") local RunService = game:GetService("RunService") local player = Players.LocalPlayer local screenGui = script.Parent screenGui.ResetOnSpawn = false local label = Instance.new("TextLabel") label.Name = "TimerLabel" label.Size = UDim2.new(0, 340, 0, 58) label.Position = UDim2.new(0.5, -170, 0, 20) label.BackgroundColor3 = Color3.fromRGB(25, 30, 45) label.BackgroundTransparency = 0.12 label.TextColor3 = Color3.fromRGB(255, 255, 255) label.TextScaled = true label.Font = Enum.Font.GothamBold label.Text = "Touch START to begin!" label.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 12) corner.Parent = label local message = Instance.new("TextLabel") message.Name = "CheckpointMessage" message.Size = UDim2.new(0, 380, 0, 42) message.Position = UDim2.new(0.5, -190, 0, 88) message.BackgroundTransparency = 1 message.TextColor3 = Color3.fromRGB(80, 240, 255) message.TextScaled = true message.Font = Enum.Font.GothamBold message.Text = "" message.Parent = screenGui local lastCheckpointMessage = "" local function formatTime(seconds) local minutes = math.floor(seconds / 60) local remainder = seconds - minutes * 60 return string.format("%02d:%05.2f", minutes, remainder) end RunService.RenderStepped:Connect(function() local active = player:GetAttribute("RunActive") local finished = player:GetAttribute("RunFinished") local startedAt = player:GetAttribute("RunStartedAt") or 0 local elapsed = player:GetAttribute("RunElapsed") or 0 if active and startedAt > 0 then elapsed = math.max(0, workspace:GetServerTimeNow() - startedAt) label.Text = "TIME " .. formatTime(elapsed) elseif finished then label.Text = "FINISHED! " .. formatTime(elapsed) else label.Text = "Touch START to begin!" end local checkpointMessage = player:GetAttribute("CheckpointMessage") or "" if checkpointMessage ~= lastCheckpointMessage then lastCheckpointMessage = checkpointMessage message.Text = checkpointMessage if checkpointMessage ~= "" then task.spawn(function() task.wait(2) if message.Text == checkpointMessage then message.Text = "" end end) end end end) 1. ObbyServer (final version) Use this complete version in ServerScriptService β†’ ObbyServer. It uses the actual frame duration when updating moving-platform velocity, making the movement less dependent on frame rate. local Players = game:GetService("Players") local RunService = game:GetService("RunService") local startSpawn = workspace:WaitForChild("StartSpawn") local oldCourse = workspace:FindFirstChild("ObbyCourse") if oldCourse then oldCourse:Destroy() end local course = Instance.new("Folder") course.Name = "ObbyCourse" course.Parent = workspace local checkpoints = {} local touchDebounce = {} local finishDebounce = {} local movingPlatforms = {} local spinningBars = {} local PLATFORM_Y = 4 local PLATFORM_SIZE = Vector3.new(10, 1, 10) local COURSE_X = {0, 18, 36, 54, 72, 90, 108, 126, 144} local baseplate = workspace:FindFirstChild("Baseplate") if baseplate then baseplate:Destroy() end for _, object in ipairs(workspace:GetDescendants()) do if object:IsA("SpawnLocation") and object ~= startSpawn then object:Destroy() end end startSpawn.Anchored = true startSpawn.CanCollide = true startSpawn.Size = PLATFORM_SIZE startSpawn.Position = Vector3.new(0, PLATFORM_Y, 0) startSpawn.Color = Color3.fromRGB(70, 200, 120) startSpawn.Neutral = true startSpawn.Duration = 0 local function makePart(name, size, position, color) local part = Instance.new("Part") part.Name = name part.Size = size part.Position = position part.Anchored = true part.CanCollide = true part.Color = color part.Material = Enum.Material.SmoothPlastic part.TopSurface = Enum.SurfaceType.Smooth part.BottomSurface = Enum.SurfaceType.Smooth part.Parent = course return part end local function getPlayerFromHit(hit) local character = hit:FindFirstAncestorOfClass("Model") if not character then return nil end return Players:GetPlayerFromCharacter(character) end local function setCheckpoint(player, position) checkpoints[player] = position player:SetAttribute("CheckpointPosition", position) end local function makeCheckpoint(x, number) local pad = makePart( "Checkpoint" .. number, Vector3.new(7, 0.35, 7), Vector3.new(x, PLATFORM_Y + 0.7, 0), Color3.fromRGB(0, 220, 255) ) pad.Material = Enum.Material.Neon pad.Touched:Connect(function(hit) local player = getPlayerFromHit(hit) if not player or touchDebounce[player] then return end touchDebounce[player] = true setCheckpoint(player, Vector3.new(x, PLATFORM_Y + 4, 0)) player:SetAttribute("CheckpointMessage", "Checkpoint " .. number .. " saved!") task.spawn(function() task.wait(1) touchDebounce[player] = nil end) end) end local function makeMovingPlatform(x, number) local part = makePart( "MovingPlatform" .. number, Vector3.new(7, 1, 7), Vector3.new(x, PLATFORM_Y + 0.5, 0), Color3.fromRGB(255, 170, 0) ) part.Material = Enum.Material.Metal table.insert(movingPlatforms, { part = part, basePosition = part.Position, phase = number * 1.7, distance = 5, speed = 1.2 }) end local function makeSpinningBar(x, number) local bar = makePart( "SpinningBar" .. number, Vector3.new(12, 0.8, 1), Vector3.new(x, PLATFORM_Y + 2, 0), Color3.fromRGB(255, 65, 65) ) bar.Material = Enum.Material.Neon table.insert(spinningBars, { part = bar, x = x, angle = 0, speed = 1.8 }) end -- Build the course. for _, x in ipairs(COURSE_X) do if x ~= 0 then makePart( "Platform", PLATFORM_SIZE, Vector3.new(x, PLATFORM_Y, 0), Color3.fromRGB(95, 120, 190) ) end end makeMovingPlatform(27, 1) makeMovingPlatform(63, 2) makeMovingPlatform(99, 3) makeCheckpoint(54, 1) makeCheckpoint(108, 2) makeSpinningBar(36, 1) makeSpinningBar(90, 2) makeSpinningBar(126, 3) local trophy = makePart( "GoldenTrophy", Vector3.new(3, 4, 3), Vector3.new(144, PLATFORM_Y + 3, 0), Color3.fromRGB(255, 210, 0) ) trophy.Shape = Enum.PartType.Ball trophy.Material = Enum.Material.Neon trophy.CanCollide = false local trophyTop = makePart( "TrophyTop", Vector3.new(4, 0.6, 4), Vector3.new(144, PLATFORM_Y + 5.2, 0), Color3.fromRGB(255, 230, 60) ) trophyTop.Shape = Enum.PartType.Cylinder trophyTop.Material = Enum.Material.Metal trophyTop.CanCollide = false local killZone = makePart( "KillZone", Vector3.new(400, 2, 100), Vector3.new(72, -20, 0), Color3.fromRGB(255, 0, 0) ) killZone.Transparency = 1 killZone.CanCollide = false killZone.Touched:Connect(function(hit) local character = hit:FindFirstAncestorOfClass("Model") local humanoid = character and character:FindFirstChildOfClass("Humanoid") if humanoid then humanoid.Health = 0 end end) local function makeLeaderstats(player) local leaderstats = Instance.new("Folder") leaderstats.Name = "leaderstats" leaderstats.Parent = player local wins = Instance.new("IntValue") wins.Name = "Wins" wins.Value = 0 wins.Parent = leaderstats end local function resetRun(player) player:SetAttribute("RunActive", false) player:SetAttribute("RunFinished", false) player:SetAttribute("RunStartedAt", 0) player:SetAttribute("RunElapsed", 0) local startPosition = startSpawn.Position + Vector3.new(0, 4, 0) setCheckpoint(player, startPosition) if player.Character then player.Character:PivotTo(CFrame.new(startPosition)) end end local function setupPlayer(player) if player:FindFirstChild("leaderstats") then return end makeLeaderstats(player) setCheckpoint(player, startSpawn.Position + Vector3.new(0, 4, 0)) player:SetAttribute("RunActive", false) player:SetAttribute("RunFinished", false) player:SetAttribute("RunStartedAt", 0) player:SetAttribute("RunElapsed", 0) player:SetAttribute("CheckpointMessage", "") player.CharacterAdded:Connect(function(character) local root = character:WaitForChild("HumanoidRootPart", 10) if not root or player.Parent ~= Players then return end local destination = checkpoints[player] or (startSpawn.Position + Vector3.new(0, 4, 0)) character:PivotTo(CFrame.new(destination)) end) if player.Character then task.spawn(function() local character = player.Character if not character then return end local root = character:WaitForChild("HumanoidRootPart", 10) if root and player.Parent == Players then character:PivotTo(CFrame.new(checkpoints[player])) end end) end end startSpawn.Touched:Connect(function(hit) local player = getPlayerFromHit(hit) if not player then return end if player:GetAttribute("RunActive") or player:GetAttribute("RunFinished") then return end player:SetAttribute("RunStartedAt", workspace:GetServerTimeNow()) player:SetAttribute("RunElapsed", 0) player:SetAttribute("RunActive", true) end) trophy.Touched:Connect(function(hit) local player = getPlayerFromHit(hit) if not player or finishDebounce[player] then return end if not player:GetAttribute("RunActive") then return end finishDebounce[player] = true local startedAt = player:GetAttribute("RunStartedAt") or 0 local elapsed = math.max(0, workspace:GetServerTimeNow() - startedAt) player:SetAttribute("RunElapsed", elapsed) player:SetAttribute("RunActive", false) player:SetAttribute("RunFinished", true) local leaderstats = player:FindFirstChild("leaderstats") local wins = leaderstats and leaderstats:FindFirstChild("Wins") if wins then wins.Value += 1 end task.spawn(function() task.wait(5) if player.Parent == Players then resetRun(player) finishDebounce[player] = nil end end) end) Players.PlayerAdded:Connect(setupPlayer) Players.PlayerRemoving:Connect(function(player) checkpoints[player] = nil touchDebounce[player] = nil finishDebounce[player] = nil end) for _, player in ipairs(Players:GetPlayers()) do setupPlayer(player) end RunService.Heartbeat:Connect(function(dt) local now = workspace:GetServerTimeNow() for _, data in ipairs(movingPlatforms) do local part = data.part local oldPosition = part.Position local offset = math.sin(now * data.speed + data.phase) * data.distance local newPosition = data.basePosition + Vector3.new(0, 0, offset) part.CFrame = CFrame.new(newPosition) part.AssemblyLinearVelocity = (newPosition - oldPosition) / math.max(dt, 1 / 240) end for _, data in ipairs(spinningBars) do data.angle += data.speed * dt data.part.CFrame = CFrame.new(data.x, PLATFORM_Y + 2, 0) * CFrame.Angles(0, data.angle, 0) end end) 2. TimerClient Type: LocalScript Put it in: StarterGui β†’ RunTimer β†’ TimerClient Paste the following complete code: local Players = game:GetService("Players") local RunService = game:GetService("RunService") local player = Players.LocalPlayer local screenGui = script.Parent screenGui.ResetOnSpawn = false local label = Instance.new("TextLabel") label.Name = "TimerLabel" label.Size = UDim2.new(0, 340, 0, 58) label.Position = UDim2.new(0.5, -170, 0, 20) label.BackgroundColor3 = Color3.fromRGB(25, 30, 45) label.BackgroundTransparency = 0.12 label.TextColor3 = Color3.fromRGB(255, 255, 255) label.TextScaled = true label.Font = Enum.Font.GothamBold label.Text = "Touch START to begin!" label.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 12) corner.Parent = label local message = Instance.new("TextLabel") message.Name = "CheckpointMessage" message.Size = UDim2.new(0, 380, 0, 42) message.Position = UDim2.new(0.5, -190, 0, 88) message.BackgroundTransparency = 1 message.TextColor3 = Color3.fromRGB(80, 240, 255) message.TextScaled = true message.Font = Enum.Font.GothamBold message.Text = "" message.Parent = screenGui local lastCheckpointMessage = "" local function formatTime(seconds) local minutes = math.floor(seconds / 60) local remainder = seconds - minutes * 60 return string.format("%02d:%05.2f", minutes, remainder) end RunService.RenderStepped:Connect(function() local active = player:GetAttribute("RunActive") local finished = player:GetAttribute("RunFinished") local startedAt = player:GetAttribute("RunStartedAt") or 0 local elapsed = player:GetAttribute("RunElapsed") or 0 if active and startedAt > 0 then elapsed = math.max(0, workspace:GetServerTimeNow() - startedAt) label.Text = "TIME " .. formatTime(elapsed) elseif finished then label.Text = "FINISHED! " .. formatTime(elapsed) else label.Text = "Touch START to begin!" end local checkpointMessage = player:GetAttribute("CheckpointMessage") or "" if checkpointMessage ~= lastCheckpointMessage then lastCheckpointMessage = checkpointMessage message.Text = checkpointMessage if checkpointMessage ~= "" then task.spawn(function() task.wait(2) if message.Text == checkpointMessage then message.Text = "" end end) end end end) 4. Test it Step 1: Start your game 1. Click the View tab and make sure Explorer and Output are visible. 2. Click the Test tab at the top. 3. Click Play. 4. Wait for your character to spawn. Expected result: the course appears, the timer is visible, and your character stands at the green starting platform. The timer may start immediately because your character touches the start platform on spawn. Step 2: Test the obstacles - Jump across the blue platforms. - Try standing on an orange moving platform. It should move back and forth. - Cross the red spinning bars carefully. - Step onto the cyan checkpoint pads. You should see a checkpoint message. - Fall off the course. Your character should respawn at the last checkpoint you touched, and the timer should continue. Step 3: Test the finish Reach the golden trophy. Expected result: - The timer stops. - The display shows FINISHED! and your time. - Your Wins value increases by one in the player list. - After five seconds, your character returns to the start for another attempt. Step 4: Fix common errors Problem | What to check Infinite yield possible on 'Workspace:WaitForChild("StartSpawn")' | Confirm the SpawnLocation is named exactly StartSpawn and is directly inside Workspace. attempt to index nil with 'Position' | Confirm StartSpawn exists and that you pasted the complete server script into ServerScriptService. Timer or checkpoint messages never appear | Confirm TimerClient is a LocalScript inside StarterGui β†’ RunTimer, and RunTimer is a ScreenGui. If something still doesn't work, click View β†’ Output, copy the red error message, and use it to identify the failing script and line number. 5. Make it feel finished Each of these touches takes less than 10 minutes. 1. Make checkpoints glow About 2 minutes In ObbyServer, inside makeCheckpoint, find pad.Material = Enum.Material.Neon. Add this line directly underneath: pad.Transparency = 0.1 The cyan checkpoints become brighter and easier to see. 2. Add a finish celebration message About 3 minutes In TimerClient, find the line: label.Text = "FINISHED! " .. formatTime(elapsed) Replace that line with: label.Text = "πŸ† COURSE COMPLETE! " .. formatTime(elapsed) Players get a more exciting finish message alongside their time. 3. Make the timer stand out About 2 minutes In TimerClient, add this line immediately after label.TextScaled = true: label.BackgroundColor3 = Color3.fromRGB(15, 100, 65) The timer gets a green background that stands out from the course. 6. Next upgrades 1. Personal best timer β€” Save each player's fastest completion time. 2. More obstacles β€” Add disappearing platforms and narrow bridges. 3. Coins and rewards β€” Place collectible coins around difficult jumps. 4. A proper trophy room β€” Show completed runs and wins on a podium. 5. Persistent progress β€” Save wins and personal best times using DataStoreService, with safe server-side saving and loading.
GPT

Roblox Game Maker With Full Lua Scripts

Add to Cart
PromptBase Select
Get this prompt + 9 more with Select$14 your first month, then $19/mo$14 first month, then $19/mo
View Select
Instant accessInstant access
Usage rightsCommercial use
Money-back guaranteeMoney‑back
By purchasing this prompt, you agree to our terms of service
GPT-6-ASTRA
Tested icon
Guide icon
4 examples icon
Free credits icon
Have a Roblox game idea but don't know how to build it? Most Roblox prompts stop at game ideas. This one gives you a small first version with a build plan and complete scripts to try in Roblox Studio. - Exactly what to create in Studio, with names and places - Complete Lua scripts, no "add your code here" - Money and wins handled on the server, a good base for fair play - Step-by-step test, common errors and fixes - For obby, tycoon, simulator and round games Beginner friendly.
...more
Added 1 day ago
Report
Browse Marketplace