Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Grab The Services
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local Players = game:GetService("Players")
- local Workspace = game:GetService("Workspace")
- local RunService = game:GetService("RunService")
- local TweenService = game:GetService("TweenService")
- -- Main Obby module
- local Obby = {}
- -- Runs when the game starts
- function Obby.OnStart()
- -- Set up all the special parts of our obby
- Obby.CreateKillParts()
- Obby.CreateSpawnLocations()
- Obby.CreateFakePlatforms()
- Obby.CreateMovingPlatforms()
- Obby.CreateChoiceDoors()
- -- When a new player joins
- Players.PlayerAdded:Connect(function(player)
- -- Make sure they have leaderstats
- if not player:FindFirstChild("leaderstats") then
- Obby.CreateLeaderstats(player)
- end
- -- When their character spawns in
- player.CharacterAdded:Connect(function(character)
- -- Store when they spawned (used for checkpoint delay)
- character:SetAttribute("SpawnTime", tick())
- -- Send them to the right spawn for their current stage
- Obby.HandlePlayerRespawn(player)
- -- Track deaths for stats
- Obby.HandlePlayerDeath(player, character)
- end)
- end)
- end
- -- Creates and sets up leaderstats (Stage and Deaths)
- function Obby.CreateLeaderstats(player)
- local leaderstats = Instance.new("Folder")
- leaderstats.Name = "leaderstats"
- leaderstats.Parent = player
- local stage = Instance.new("NumberValue", leaderstats)
- stage.Name = "Stage"
- stage.Value = 1 -- Everyone starts at stage 1
- local deaths = Instance.new("NumberValue", leaderstats)
- deaths.Name = "Deaths"
- deaths.Value = 0
- end
- -- Teleports the player to the correct spawn based on their current stage
- function Obby.HandlePlayerRespawn(player)
- local leaderstats = player:FindFirstChild("leaderstats")
- if not leaderstats then return end
- local stageValue = leaderstats:FindFirstChild("Stage")
- if not stageValue then return end
- local stage = stageValue.Value
- local stageFolder = Workspace.Stages:FindFirstChild(tostring(stage))
- if not stageFolder then return end
- local spawnLocation = stageFolder:FindFirstChild("SpawnLocation")
- if not spawnLocation then return end
- -- Preload the area before teleporting the player
- player:RequestStreamAroundAsync(spawnLocation.Position)
- local character = player.Character
- if character then
- character:PivotTo(spawnLocation.CFrame)
- end
- end
- -- When the player dies, increase their death count
- function Obby.HandlePlayerDeath(player, character)
- local humanoid = character:FindFirstChildOfClass("Humanoid")
- if humanoid then
- humanoid.Died:Connect(function()
- local leaderstats = player:FindFirstChild("leaderstats")
- if leaderstats then
- local deaths = leaderstats:FindFirstChild("Deaths")
- if deaths then
- deaths.Value += 1
- end
- end
- end)
- end
- end
- -- Makes a portal teleport anything that touches it to a destination point
- function Obby.CreatePortal(portal, destination)
- portal.Touched:Connect(function(other)
- local char = other.Parent
- local root = char and char:FindFirstChild("HumanoidRootPart")
- if root then
- -- Move the player a little above the destination so they don’t get stuck
- root.CFrame = destination * CFrame.new(0, 3, 0)
- end
- end)
- end
- -- Detects when players touch spawn locations and updates their checkpoint
- function Obby.CreateSpawnLocations()
- for _, spawn in ipairs(Workspace.Stages:GetDescendants()) do
- if spawn:IsA("SpawnLocation") then
- spawn.Touched:Connect(function(otherPart)
- local character = otherPart.Parent
- if not character or not character:IsA("Model") then return end
- local player = Players:GetPlayerFromCharacter(character)
- if not player then return end
- -- Don't let the spawn trigger instantly after respawn
- local spawnTime = character:GetAttribute("SpawnTime")
- if spawnTime and tick() - spawnTime < 2 then return end
- local leaderstats = player:FindFirstChild("leaderstats")
- if not leaderstats then return end
- local stageValue = leaderstats:FindFirstChild("Stage")
- if not stageValue then return end
- local newStage = tonumber(spawn.Parent.Name)
- if newStage and newStage > stageValue.Value then
- stageValue.Value = newStage
- Obby.ShowCheckpointUI(player)
- end
- end)
- end
- end
- end
- -- These parts kill the player when touched
- function Obby.CreateKillParts()
- for _, part in ipairs(Workspace.Stages:GetDescendants()) do
- if part:IsA("BasePart") and part.Name == "Kill" then
- part.Touched:Connect(function(otherPart)
- local character = otherPart.Parent
- if character and character:IsA("Model") then
- local humanoid = character:FindFirstChildOfClass("Humanoid")
- if humanoid and humanoid.Health > 0 then
- humanoid.Health = 0 -- Instant death
- end
- end
- end)
- end
- end
- end
- -- Platforms that disappear temporarily after being touched
- function Obby.CreateFakePlatforms()
- for _, part in ipairs(Workspace.Stages:GetDescendants()) do
- if part:IsA("BasePart") and part.Name == "FakePlatform" then
- part.Touched:Connect(function(otherPart)
- local character = otherPart.Parent
- if character and character:IsA("Model") then
- task.wait(0.0) -- Let them land first
- part.Transparency = 1
- part.CanCollide = false
- task.wait(3) -- Bring it back after 3 seconds
- part.Transparency = 0
- part.CanCollide = true
- end
- end)
- end
- end
- end
- -- Moves platforms back and forth using TweenService
- function Obby.CreateMovingPlatforms()
- for _, platform in ipairs(Workspace.Stages:GetDescendants()) do
- if platform:IsA("BasePart") and platform.Name == "MovingPlatform" then
- local targetPosition = platform:GetAttribute("TargetPosition")
- local moveTime = platform:GetAttribute("MoveTime") or 3
- local waitTime = platform:GetAttribute("WaitTime") or 1
- if targetPosition then
- local startPos = platform.Position
- local endPos = Vector3.new(targetPosition.X, targetPosition.Y, targetPosition.Z)
- local tweenInfo = TweenInfo.new(
- moveTime,
- Enum.EasingStyle.Sine,
- Enum.EasingDirection.InOut,
- -1, -- Infinite loops
- true -- Ping-pong back and forth
- )
- local tween = TweenService:Create(platform, tweenInfo, {Position = endPos})
- tween:Play()
- -- This keeps the platform's velocity synced so characters ride it smoothly
- local lastPosition = platform.Position
- RunService.Stepped:Connect(function(_, deltatime)
- local currentPosition = platform.Position
- local deltaPosition = currentPosition - lastPosition
- local velocity = deltaPosition / deltatime
- platform.AssemblyLinearVelocity = velocity
- lastPosition = currentPosition
- end)
- end
- end
- end
- end
- -- Handles a level where players choose between deadly or safe doors
- function Obby.CreateChoiceDoors()
- local stages = Workspace:FindFirstChild("Stages")
- if not stages then return end
- local choiceDoors = stages:FindFirstChild("20") -- Only runs if stage 20 exists
- if not choiceDoors then return end
- for _, doorModel in ipairs(choiceDoors:GetChildren()) do
- if doorModel:IsA("Model") then
- local trapDoor = doorModel:FindFirstChild("TrapDoor")
- local rightDoor = doorModel:FindFirstChild("RightDoor")
- -- Trap door kills you if you touch it
- if trapDoor and trapDoor:IsA("BasePart") then
- trapDoor.Touched:Connect(function(otherPart)
- local character = otherPart.Parent
- local humanoid = character and character:FindFirstChildOfClass("Humanoid")
- if humanoid and humanoid.Health > 0 then
- humanoid.Health = 0
- end
- end)
- end
- -- Right door lets you through temporarily
- if rightDoor and rightDoor:IsA("BasePart") then
- rightDoor.Touched:Connect(function(otherPart)
- local character = otherPart.Parent
- local humanoid = character and character:FindFirstChildOfClass("Humanoid")
- if humanoid then
- rightDoor.CanCollide = false
- rightDoor.Transparency = 0.5
- task.wait(2)
- rightDoor.CanCollide = true
- rightDoor.Transparency = 0.35
- end
- end)
- end
- end
- end
- end
- -- Shows a little UI popup when a checkpoint is reached
- function Obby.ShowCheckpointUI(player)
- local playerGui = player:FindFirstChildOfClass("PlayerGui")
- if not playerGui then return end
- local existingUI = playerGui:FindFirstChild("CheckpointUI")
- local ui
- if existingUI then
- ui = existingUI
- else
- local template = ReplicatedStorage:FindFirstChild("CheckpointUI")
- if not template then return end
- ui = template:Clone()
- ui.Parent = playerGui
- end
- local label = ui:FindFirstChildOfClass("TextLabel")
- if not label then return end
- label.Visible = true
- label.TextTransparency = 1
- -- Fade in the text
- for i = 0, 1, 0.1 do
- label.TextTransparency = 1 - i
- task.wait(0.03)
- end
- task.wait(0.4)
- -- Fade it back out
- for i = 0, 1, 0.1 do
- label.TextTransparency = i
- task.wait(0.03)
- end
- label.Visible = false
- end
- -- return the module
- return Obby
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement