# šŸŽ® Roblox Obby Game: "Sky Jump Challenge" A complete beginner-friendly obby game with coins, levels, shop, and respawn system. --- ## šŸ“ Project Structure ``` game/ ā”œā”€ā”€ ServerScriptService/ │ ā”œā”€ā”€ GameManager.lua (ServerScript) │ └── ShopHandler.lua (ServerScript) ā”œā”€ā”€ ReplicatedStorage/ │ └── GameConfig.lua (ModuleScript) ā”œā”€ā”€ StarterGui/ │ └── GameUI.lua (LocalScript inside ScreenGui) ā”œā”€ā”€ StarterPlayerScripts/ │ └── ClientController.lua (LocalScript) └── Workspace/ └── (Obby parts, checkpoints, coins created via script or manually) ``` --- ## šŸ“œ Scripts ### 1. GameConfig (ModuleScript) - `ReplicatedStorage/GameConfig` ```lua local GameConfig = {} GameConfig.StartingCoins = 0 GameConfig.StartingLevel = 1 GameConfig.MaxLevel = 10 GameConfig.LevelRequirements = { [1] = 0, [2] = 50, [3] = 150, [4] = 300, [5] = 500, [6] = 750, [7] = 1000, [8] = 1500, [9] = 2000, [10] = 3000 } GameConfig.ShopItems = { SpeedBoost = { Price = 100, Multiplier = 1.5, Duration = 30 }, DoubleCoins = { Price = 200, Multiplier = 2, Duration = 60 }, ExtraJump = { Price = 150, JumpPower = 60 } } GameConfig.CoinValues = { Bronze = 1, Silver = 5, Gold = 10 } return GameConfig ``` --- ### 2. GameManager (ServerScript) - `ServerScriptService/GameManager` ```lua local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local DataStoreService = game:GetService("DataStoreService") local GameConfig = require(ReplicatedStorage:WaitForChild("GameConfig")) local PlayerDataStore = DataStoreService:GetDataStore("PlayerData_v1") local PlayerDataEvent = Instance.new("RemoteEvent") PlayerDataEvent.Name = "PlayerDataEvent" PlayerDataEvent.Parent = ReplicatedStorage local CoinCollectedEvent = Instance.new("RemoteEvent") CoinCollectedEvent.Name = "CoinCollectedEvent" CoinCollectedEvent.Parent = ReplicatedStorage local CheckpointEvent = Instance.new("RemoteEvent") CheckpointEvent.Name = "CheckpointEvent" CheckpointEvent.Parent = ReplicatedStorage local playerData = {} local function loadPlayerData(player) local userId = player.UserId local key = "Player_" .. userId local success, data = pcall(function() return PlayerDataStore:GetAsync(key) end) if success and data then playerData[userId] = data else playerData[userId] = { Coins = GameConfig.StartingCoins, Level = GameConfig.StartingLevel, Checkpoint = 1, OwnedItems = {} } end PlayerDataEvent:FireClient(player, "DataLoaded", playerData[userId]) end local function savePlayerData(player) local userId = player.UserId local key = "Player_" .. userId if playerData[userId] then pcall(function() PlayerDataStore:SetAsync(key, playerData[userId]) end) end end local function setupLeaderstats(player) local leaderstats = Instance.new("Folder") leaderstats.Name = "leaderstats" leaderstats.Parent = player local coins = Instance.new("IntValue") coins.Name = "Coins" coins.Parent = leaderstats local level = Instance.new("IntValue") level.Name = "Level" level.Parent = leaderstats return leaderstats end local function updateLeaderstats(player) local userId = player.UserId local data = playerData[userId] if data and player:FindFirstChild("leaderstats") then player.leaderstats.Coins.Value = data.Coins player.leaderstats.Level.Value = data.Level end end local function checkLevelUp(player) local userId = player.UserId local data = playerData[userId] if not data then return end local currentLevel = data.Level local nextLevel = currentLevel + 1 if nextLevel <= GameConfig.MaxLevel then local requiredCoins = GameConfig.LevelRequirements[nextLevel] if data.Coins >= requiredCoins then data.Level = nextLevel PlayerDataEvent:FireClient(player, "LevelUp", nextLevel) updateLeaderstats(player) end end end local function addCoins(player, amount) local userId = player.UserId if playerData[userId] then playerData[userId].Coins = playerData[userId].Coins + amount updateLeaderstats(player) checkLevelUp(player) PlayerDataEvent:FireClient(player, "CoinsUpdated", playerData[userId].Coins) end end local function spawnPlayer(player, checkpointNumber) local character = player.Character if not character then return end local checkpoints = workspace:FindFirstChild("Checkpoints") if checkpoints then local checkpoint = checkpoints:FindFirstChild("Checkpoint" .. checkpointNumber) if checkpoint then local hrp = character:FindFirstChild("HumanoidRootPart") if hrp then hrp.CFrame = checkpoint.CFrame + Vector3.new(0, 5, 0) end end end end Players.PlayerAdded:Connect(function(player) setupLeaderstats(player) loadPlayerData(player) player.CharacterAdded:Connect(function(character) task.wait(0.5) updateLeaderstats(player) local userId = player.UserId if playerData[userId] then spawnPlayer(player, playerData[userId].Checkpoint) end local humanoid = character:FindFirstChild("Humanoid") if humanoid then humanoid.Died:Connect(function() task.wait(3) player:LoadCharacter() end) end end) end) Players.PlayerRemoving:Connect(function(player) savePlayerData(player) playerData[player.UserId] = nil end) game:BindToClose(function() for _, player in pairs(Players:GetPlayers()) do savePlayerData(player) end end) CoinCollectedEvent.OnServerEvent:Connect(function(player, coinType) local value = GameConfig.CoinValues[coinType] or 1 addCoins(player, value) end) CheckpointEvent.OnServerEvent:Connect(function(player, checkpointNumber) local userId = player.UserId if playerData[userId] then if checkpointNumber > playerData[userId].Checkpoint then playerData[userId].Checkpoint = checkpointNumber PlayerDataEvent:FireClient(player, "CheckpointReached", checkpointNumber) end end end) local function getPlayerData(player) return playerData[player.UserId] end return { GetPlayerData = getPlayerData, AddCoins = addCoins } ``` --- ### 3. ShopHandler (ServerScript) - `ServerScriptService/ShopHandler` ```lua local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local GameConfig = require(ReplicatedStorage:WaitForChild("GameConfig")) local ShopEvent = Instance.new("RemoteEvent") ShopEvent.Name = "ShopEvent" ShopEvent.Parent = ReplicatedStorage local PlayerDataEvent = ReplicatedStorage:WaitForChild("PlayerDataEvent") local activePowerups = {} local function applySpeedBoost(player, multiplier, duration) local character = player.Character if not character then return end local humanoid = character:FindFirstChild("Humanoid") if humanoid then local originalSpeed = 16 humanoid.WalkSpeed = originalSpeed * multiplier task.delay(duration, function() if humanoid and humanoid.Parent then humanoid.WalkSpeed = originalSpeed end end) end end local function applyExtraJump(player, jumpPower) local character = player.Character if not character then return end local humanoid = character:FindFirstChild("Humanoid") if humanoid then humanoid.JumpPower = jumpPower end end ShopEvent.OnServerEvent:Connect(function(player, action, itemName) if action ~= "Purchase" then return end local item = GameConfig.ShopItems[itemName] if not item then return end local leaderstats = player:FindFirstChild("leaderstats") if not leaderstats then return end local coins = leaderstats:FindFirstChild("Coins") if not coins or coins.Value < item.Price then ShopEvent:FireClient(player, "PurchaseFailed", "Not enough coins!") return end coins.Value = coins.Value - item.Price PlayerDataEvent:FireClient(player, "CoinsUpdated", coins.Value) if itemName == "SpeedBoost" then applySpeedBoost(player, item.Multiplier, item.Duration) elseif itemName == "ExtraJump" then applyExtraJump(player, item.JumpPower) elseif itemName == "DoubleCoins" then activePowerups[player.UserId] = activePowerups[player.UserId] or {} activePowerups[player.UserId].DoubleCoins = true task.delay(item.Duration, function() if activePowerups[player.UserId] then activePowerups[player.UserId].DoubleCoins = nil end end) end ShopEvent:FireClient(player, "PurchaseSuccess", itemName) end) Players.PlayerRemoving:Connect(function(player) activePowerups[player.UserId] = nil end) ``` --- ### 4. GameUI (LocalScript) - `StarterGui/GameUI` (inside a ScreenGui) First, create a **ScreenGui** in StarterGui, then put this LocalScript inside it: ```lua local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local TweenService = game:GetService("TweenService") local player = Players.LocalPlayer local PlayerDataEvent = ReplicatedStorage:WaitForChild("PlayerDataEvent") local ShopEvent = ReplicatedStorage:WaitForChild("ShopEvent") local GameConfig = require(ReplicatedStorage:WaitForChild("GameConfig")) local screenGui = script.Parent local function createMainUI() local mainFrame = Instance.new("Frame") mainFrame.Name = "MainUI" mainFrame.Size = UDim2.new(0, 200, 0, 80) mainFrame.Position = UDim2.new(0, 10, 0, 10) mainFrame.BackgroundColor3 = Color3.fromRGB(30, 30, 40) mainFrame.BackgroundTransparency = 0.3 mainFrame.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 12) corner.Parent = mainFrame local coinLabel = Instance.new("TextLabel") coinLabel.Name = "CoinLabel" coinLabel.Size = UDim2.new(1, -20, 0, 35) coinLabel.Position = UDim2.new(0, 10, 0, 5) coinLabel.BackgroundTransparency = 1 coinLabel.Text = "šŸŖ™ Coins: 0" coinLabel.TextColor3 = Color3.fromRGB(255, 215, 0) coinLabel.TextSize = 22 coinLabel.Font = Enum.Font.GothamBold coinLabel.TextXAlignment = Enum.TextXAlignment.Left coinLabel.Parent = mainFrame local levelLabel = Instance.new("TextLabel") levelLabel.Name = "LevelLabel" levelLabel.Size = UDim2.new(1, -20, 0, 35) levelLabel.Position = UDim2.new(0, 10, 0, 40) levelLabel.BackgroundTransparency = 1 levelLabel.Text = "⭐ Level: 1" levelLabel.TextColor3 = Color3.fromRGB(100, 200, 255) levelLabel.TextSize = 22 levelLabel.Font = Enum.Font.GothamBold levelLabel.TextXAlignment = Enum.TextXAlignment.Left levelLabel.Parent = mainFrame return mainFrame end local function createShopButton() local shopButton = Instance.new("TextButton") shopButton.Name = "ShopButton" shopButton.Size = UDim2.new(0, 80, 0, 80) shopButton.Position = UDim2.new(1, -90, 0.5, -40) shopButton.BackgroundColor3 = Color3.fromRGB(50, 180, 100) shopButton.Text = "šŸ›’\nShop" shopButton.TextColor3 = Color3.fromRGB(255, 255, 255) shopButton.TextSize = 18 shopButton.Font = Enum.Font.GothamBold shopButton.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 12) corner.Parent = shopButton return shopButton end local function createShopUI() local shopFrame = Instance.new("Frame") shopFrame.Name = "ShopFrame" shopFrame.Size = UDim2.new(0, 300, 0, 350) shopFrame.Position = UDim2.new(0.5, -150, 0.5, -175) shopFrame.BackgroundColor3 = Color3.fromRGB(40, 40, 50) shopFrame.Visible = false shopFrame.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 16) corner.Parent = shopFrame local title = Instance.new("TextLabel") title.Size = UDim2.new(1, 0, 0, 50) title.BackgroundTransparency = 1 title.Text = "šŸ›’ SHOP" title.TextColor3 = Color3.fromRGB(255, 255, 255) title.TextSize = 28 title.Font = Enum.Font.GothamBold title.Parent = shopFrame local closeButton = Instance.new("TextButton") closeButton.Size = UDim2.new(0, 40, 0, 40) closeButton.Position = UDim2.new(1, -45, 0, 5) closeButton.BackgroundColor3 = Color3.fromRGB(200, 60, 60) closeButton.Text = "X" closeButton.TextColor3 = Color3.fromRGB(255, 255, 255) closeButton.TextSize = 20 closeButton.Font = Enum.Font.GothamBold closeButton.Parent = shopFrame local closeCorner = Instance.new("UICorner") closeCorner.CornerRadius = UDim.new(0, 8) closeCorner.Parent = closeButton local yPos = 60 for itemName, itemData in pairs(GameConfig.ShopItems) do local itemButton = Instance.new("TextButton") itemButton.Name = itemName itemButton.Size = UDim2.new(0.9, 0, 0, 60) itemButton.Position = UDim2.new(0.05, 0, 0, yPos) itemButton.BackgroundColor3 = Color3.fromRGB(60, 60, 80) itemButton.Text = itemName .. "\nšŸ’° " .. itemData.Price .. " Coins" itemButton.TextColor3 = Color3.fromRGB(255, 255, 255) itemButton.TextSize = 16 itemButton.Font = Enum.Font.GothamBold itemButton.Parent = shopFrame local itemCorner = Instance.new("UICorner") itemCorner.CornerRadius = UDim.new(0, 10) itemCorner.Parent = itemButton itemButton.MouseButton1Click:Connect(function() ShopEvent:FireServer("Purchase", itemName) end) yPos = yPos + 70 end closeButton.MouseButton1Click:Connect(function() shopFrame.Visible = false end) return shopFrame end local function createNotification(text, color) local notification = Instance.new("TextLabel") notification.Size = UDim2.new(0, 300, 0, 50) notification.Position = UDim2.new(0.5, -150, 0, -60) notification.BackgroundColor3 = color or Color3.fromRGB(50, 50, 60) notification.BackgroundTransparency = 0.2 notification.Text = text notification.TextColor3 = Color3.fromRGB(255, 255, 255) notification.TextSize = 20 notification.Font = Enum.Font.GothamBold notification.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 12) corner.Parent = notification local tweenIn = TweenService:Create(notification, TweenInfo.new(0.3), { Position = UDim2.new(0.5, -150, 0, 20) }) tweenIn:Play() task.delay(2, function() local tweenOut = TweenService:Create(notification, TweenInfo.new(0.3), { Position = UDim2.new(0.5, -150, 0, -60) }) tweenOut:Play() tweenOut.Completed:Connect(function() notification:Destroy() end) end) end local mainUI = createMainUI() local shopButton = createShopButton() local shopFrame = createShopUI() shopButton.MouseButton1Click:Connect(function() shopFrame.Visible = not shopFrame.Visible end) PlayerDataEvent.OnClientEvent:Connect(function(action, data) if action == "DataLoaded" then mainUI.CoinLabel.Text = "šŸŖ™ Coins: " .. data.Coins mainUI.LevelLabel.Text = "⭐ Level: " .. data.Level elseif action == "CoinsUpdated" then mainUI.CoinLabel.Text = "šŸŖ™ Coins: " .. data elseif action == "LevelUp" then mainUI.LevelLabel.Text = "⭐ Level: " .. data createNotification("šŸŽ‰ LEVEL UP! Level " .. data, Color3.fromRGB(100, 200, 100)) elseif action == "CheckpointReached" then createNotification("āœ… Checkpoint " .. data .. " Reached!", Color3.fromRGB(100, 150, 255)) end end) ShopEvent.OnClientEvent:Connect(function(action, data) if action == "PurchaseSuccess" then createNotification("āœ… Purchased: " .. data, Color3.fromRGB(100, 200, 100)) elseif action == "PurchaseFailed" then createNotification("āŒ " .. data, Color3.fromRGB(200, 100, 100)) end end) ``` --- ### 5. ClientController (LocalScript) - `StarterPlayerScripts/ClientController` ```lua local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local RunService = game:GetService("RunService") local player = Players.LocalPlayer local CoinCollectedEvent = ReplicatedStorage:WaitForChild("CoinCollectedEvent") local CheckpointEvent = ReplicatedStorage:WaitForChild("CheckpointEvent") local collectedCoins = {} local touchedCheckpoints = {} local function setupCoinCollection() local coinsFolder = workspace:FindFirstChild("Coins") if not coinsFolder then return end for _, coin in pairs(coinsFolder:GetChildren()) do if coin:IsA("BasePart") then coin.Touched:Connect(function(hit) local character = player.Character if not character then return end local humanoid = character:FindFirstChild("Humanoid") if not humanoid then return end if hit:IsDescendantOf(character) and not collectedCoins[coin] then collectedCoins[coin] = true local coinType = coin:GetAttribute("CoinType") or "Bronze" CoinCollectedEvent:FireServer(coinType) coin.Transparency = 1 coin.CanCollide = false task.delay(10, function() collectedCoins[coin] = nil coin.Transparency = 0 coin.CanCollide = false end) end end) end end end local function setupCheckpoints() local checkpointsFolder = workspace:FindFirstChild("Checkpoints") if not checkpointsFolder then return end for _, checkpoint in pairs(checkpointsFolder:GetChildren()) do if checkpoint:IsA("BasePart") then checkpoint.Touched:Connect(function(hit) local character = player.Character if not character then return end local humanoid = character:FindFirstChild("Humanoid") if not humanoid then return end if hit:IsDescendantOf(character) then local checkpointNumber = tonumber(checkpoint.Name:match("%d+")) or 1 if not touchedCheckpoints[checkpointNumber] then touchedCheckpoints[checkpointNumber] = true CheckpointEvent:FireServer(checkpointNumber) end end end) end end end local function setupKillBricks() local killBricksFolder = workspace:FindFirstChild("KillBricks") if not killBricksFolder then return end for _, killBrick in pairs(killBricksFolder:GetChildren()) do if killBrick:IsA("BasePart") then killBrick.Touched:Connect(function(hit) local character = player.Character if not character then return end local humanoid = character:FindFirstChild("Humanoid") if humanoid and hit:IsDescendantOf(character) then humanoid.Health = 0 end end) end end end player.CharacterAdded:Connect(function() task.wait(1) setupCoinCollection() setupCheckpoints() setupKillBricks() end) if player.Character then setupCoinCollection() setupCheckpoints() setupKillBricks() end ``` --- ### 6. ObbyBuilder (ServerScript) - `ServerScriptService/ObbyBuilder` This script creates the obby automatically: ```lua local function createPart(name, size, position, color, parent, anchored) local part = Instance.new("Part") part.Name = name part.Size = size part.Position = position part.Color = color part.Anchored = anchored ~= false part.Material = Enum.Material.SmoothPlastic part.Parent = parent return part end local function createCoin(name, position, coinType, parent) local coin = Instance.new("Part") coin.Name = name coin.Shape = Enum.PartType.Cylinder coin.Size = Vector3.new(0.5, 2, 2) coin.Position = position coin.Orientation = Vector3.new(0, 0, 90) coin.Anchored = true coin.CanCollide = false coin.Material = Enum.Material.Neon coin:SetAttribute("CoinType", coinType) if coinType == "Gold" then coin.Color = Color3.fromRGB(255, 215, 0) elseif coinType == "Silver" then coin.Color = Color3.fromRGB(192, 192, 192) else coin.Color = Color3.fromRGB(205, 127, 50) end coin.Parent = parent task.spawn(function() while coin and coin.Parent do for i = 0, 360, 5 do if not coin or not coin.Parent then break end coin.Orientation = Vector3.new(0, i, 90) task.wait(0.03) end end end) return coin end local checkpointsFolder = Instance.new("Folder") checkpointsFolder.Name = "Checkpoints" checkpointsFolder.Parent = workspace local coinsFolder = Instance.new("Folder") coinsFolder.Name = "Coins" coinsFolder.Parent = workspace local killBricksFolder = Instance.new("Folder") killBricksFolder.Name = "KillBricks" killBricksFolder.Parent = workspace local platformsFolder = Instance.new("Folder") platformsFolder.Name = "Platforms" platformsFolder.Parent = workspace local startPlatform = createPart("StartPlatform", Vector3.new(20, 2, 20), Vector3.new(0, 0, 0), Color3.fromRGB(100, 200, 100), platformsFolder) local checkpoint1 = createPart("Checkpoint1", Vector3.new(5, 1, 5), Vector3.new(0, 1.5, 0), Color3.fromRGB(0, 255, 0), checkpointsFolder) checkpoint1.Transparency = 0.5 local positions = { Vector3.new(15, 5, 0), Vector3.new(25, 10, 5), Vector3.new(35, 15, -5), Vector3.new(45, 20, 0), Vector3.new(55, 25, 10), } for i, pos in ipairs(positions) do local platform = createPart("Platform" .. i, Vector3.new(6, 2, 6), pos, Color3.fromRGB(80, 80, 200), platformsFolder) createCoin("Coin" .. i, pos + Vector3.new(0, 3, 0), "Bronze", coinsFolder) end local checkpoint2 = createPart("Checkpoint2", Vector3.new(10, 2, 10), Vector3.new(65, 30, 0), Color3.fromRGB(100, 200, 100), checkpointsFolder) local checkpoint2Marker = createPart("Checkpoint2Marker", Vector3.new(5, 1, 5), Vector3.new(65, 31.5, 0), Color3.fromRGB(0, 255, 0), checkpointsFolder) checkpoint2Marker.Transparency = 0.5 checkpoint2Marker.Name = "Checkpoint2" checkpoint2:Destroy() createCoin("GoldCoin1", Vector3.new(65, 35, 0), "Gold", coinsFolder) local killBrick = createPart("KillBrick1", Vector3.new(30, 1, 30), Vector3.new(30, -10, 0), Color3.fromRGB(255, 0, 0), killBricksFolder) killBrick.Material = Enum.Material.Neon print("Obby built successfully!") ``` --- ## šŸ“ Where to Put Each Script in Roblox Studio | Script Name | Type | Location | |-------------|------|----------| | GameConfig | ModuleScript | ReplicatedStorage | | GameManager | Script (Server) | ServerScriptService | | ShopHandler | Script (Server) | ServerScriptService | | ObbyBuilder | Script (Server) | ServerScriptService | | GameUI | LocalScript | StarterGui → ScreenGui | | ClientController | LocalScript | StarterPlayerScripts | --- ## šŸ’° Monetization Ideas ### Game Passes (One-time purchase) 1. **VIP Pass** (199 Robux) - 2x coins permanently, special badge 2. **Speed Master** (99 Robux) - 25% faster walk speed 3. **Skip Levels** (149 Robux) - Ability to skip difficult stages 4. **Rainbow Trail** (49 Robux) - Colorful trail effect ### Developer Products (Repeatable) 1. **100 Coins** (10 Robux) 2. **500 Coins** (45 Robux) 3. **Instant Revive** (5 Robux) 4. **Temporary Speed Boost** (15 Robux) --- ## šŸš€ How to Publish on Roblox 1. **Open Roblox Studio** and create your game 2. **Add all scripts** to their proper locations 3. **Test the game** using Play (F5) 4. **File → Publish to Roblox** 5. Choose **Create new game** or update existing 6. Set **Name**, **Description**, and **Genre** 7. **Configure Game Settings:** - Game Settings → Basic Info → Set icon and thumbnails - Permissions → Set to Public when ready - Monetization → Enable paid access or free 8. **Enable DataStore** in Game Settings → Security 9. Click **Save** and your game is live! --- ## šŸŽÆ Game Name Suggestions 1. Sky Jump Challenge 2. Obby Masters 3. Cloud Climbers 4. Jump & Collect 5. Parkour Paradise 6. Coin Rush Obby --- ## ⚔ Performance Tips - Keep part count under 10,000 - Use `Anchored = true` for static parts - Avoid using `while true do` without `task.wait()` - Use RemoteEvents instead of RemoteFunctions when possible - Batch DataStore saves (don't save every second)