Fun client side ball script [MOBILE SUPPORTED]
Key RequiredUniversal

Fun client side ball script [MOBILE SUPPORTED]

Universal Script*108192*108192 3.2K views 218 executesUpdated Sep 8, 2025
5.0/ 5(1 votes)
10100% Positive
Lua Script•398 lines (13727 chars)
-- LocalScript in StarterPlayerScripts

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Debris = game:GetService("Debris")

local player = Players.LocalPlayer
local spawnedBalls = {}
local grabbableMode = false
local grabbedBall = nil
local grabOffset = Vector3.new()
local activeFunConnection

-- Helper functions
local function getCharacter()
    return player.Character or player.CharacterAdded:Wait()
end

local function getHRP()
    return getCharacter():WaitForChild("HumanoidRootPart")
end

local function updateLabel(label)
    label.Text = "Spawned balls: "..#spawnedBalls
end

-- UI Setup
local screenGui = Instance.new("ScreenGui")
screenGui.Name = "BallManagerUI"
screenGui.ResetOnSpawn = false
screenGui.Parent = player:WaitForChild("PlayerGui")

local function makeDraggable(frame)
    local dragging, dragInput, dragStart, startPos
    frame.InputBegan:Connect(function(input)
        if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
            dragging = true
            dragStart = input.Position
            startPos = frame.Position
            input.Changed:Connect(function()
                if input.UserInputState == Enum.UserInputState.End then
                    dragging = false
                end
            end)
        end
    end)
    frame.InputChanged:Connect(function(input)
        if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
            dragInput = input
        end
    end)
    UserInputService.InputChanged:Connect(function(input)
        if dragging and input == dragInput then
            local delta = input.Position - dragStart
            frame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
        end
    end)
end

-- Main Frame
local frame = Instance.new("Frame")
frame.Size = UDim2.new(0, 300, 0, 330)
frame.Position = UDim2.new(0.5, -150, 0.5, -165)
frame.BackgroundColor3 = Color3.fromRGB(50,50,50)
frame.Parent = screenGui
makeDraggable(frame)

-- Title
local title = Instance.new("TextLabel")
title.Size = UDim2.new(1,0,0,30)
title.BackgroundTransparency = 1
title.Text = "Ball Management"
title.TextColor3 = Color3.new(1,1,1)
title.Font = Enum.Font.SourceSansBold
title.TextSize = 20
title.Parent = frame

-- Close Button
local xButton = Instance.new("TextButton")
xButton.Size = UDim2.new(0,30,0,30)
xButton.Position = UDim2.new(1,-35,0,5)
xButton.Text = "X"
xButton.TextScaled = true
xButton.BackgroundColor3 = Color3.fromRGB(170,0,0)
xButton.Parent = frame

-- Amount input
local amountBox = Instance.new("TextBox")
amountBox.Size = UDim2.new(0,100,0,30)
amountBox.Position = UDim2.new(0,10,0,50)
amountBox.PlaceholderText = "Amount"
amountBox.Text = ""
amountBox.TextScaled = true
amountBox.Parent = frame

-- Spawn Button
local spawnButton = Instance.new("TextButton")
spawnButton.Size = UDim2.new(0,100,0,30)
spawnButton.Position = UDim2.new(0,10,0,90)
spawnButton.Text = "Spawn Balls"
spawnButton.TextScaled = true
spawnButton.BackgroundColor3 = Color3.fromRGB(0,170,0)
spawnButton.Parent = frame

-- Delete All
local deleteAllButton = Instance.new("TextButton")
deleteAllButton.Size = UDim2.new(0,100,0,30)
deleteAllButton.Position = UDim2.new(0,10,0,130)
deleteAllButton.Text = "Delete All Balls"
deleteAllButton.TextScaled = true
deleteAllButton.BackgroundColor3 = Color3.fromRGB(170,0,0)
deleteAllButton.Parent = frame

-- Delete Amount
local deleteAmountButton = Instance.new("TextButton")
deleteAmountButton.Size = UDim2.new(0,100,0,30)
deleteAmountButton.Position = UDim2.new(0,130,0,90)
deleteAmountButton.Text = "Delete Amount"
deleteAmountButton.TextScaled = true
deleteAmountButton.BackgroundColor3 = Color3.fromRGB(255,140,0)
deleteAmountButton.Parent = frame

-- Emergency Recovery
local emergencyButton = Instance.new("TextButton")
emergencyButton.Size = UDim2.new(0,220,0,30)
emergencyButton.Position = UDim2.new(0,10,0,170)
emergencyButton.Text = "Emergency Recovery"
emergencyButton.TextScaled = true
emergencyButton.BackgroundColor3 = Color3.fromRGB(0,0,255)
emergencyButton.Parent = frame

-- Grabbable Mode
local grabbableButton = Instance.new("TextButton")
grabbableButton.Size = UDim2.new(0,220,0,30)
grabbableButton.Position = UDim2.new(0,10,0,210)
grabbableButton.Text = "Toggle Grabbable Balls: OFF"
grabbableButton.TextScaled = true
grabbableButton.BackgroundColor3 = Color3.fromRGB(100,100,255)
grabbableButton.Parent = frame

-- Fun Button
local funButton = Instance.new("TextButton")
funButton.Size = UDim2.new(0,220,0,30)
funButton.Position = UDim2.new(0,10,0,250)
funButton.Text = "Fun"
funButton.TextScaled = true
funButton.BackgroundColor3 = Color3.fromRGB(255,100,255)
funButton.Parent = frame

-- Spawned balls label
local spawnedLabel = Instance.new("TextLabel")
spawnedLabel.Size = UDim2.new(0,240,0,30)
spawnedLabel.Position = UDim2.new(0,10,0,290)
spawnedLabel.BackgroundTransparency = 1
spawnedLabel.TextColor3 = Color3.new(1,1,1)
spawnedLabel.TextScaled = true
spawnedLabel.Text = "Spawned balls: 0"
spawnedLabel.Parent = frame

-- Ball Functions
local function spawnBalls(amount)
    local hrp = getHRP()
    for i = 1, amount do
        local ball = Instance.new("Part")
        ball.Shape = Enum.PartType.Ball
        ball.Size = Vector3.new(1,1,1)
        ball.Position = hrp.Position + hrp.CFrame.LookVector * (5+i) + hrp.CFrame.RightVector * ((i%3)-1) * 2
        ball.Anchored = false
        ball.BrickColor = BrickColor.random()
        ball.Parent = workspace
        table.insert(spawnedBalls, ball)

        local bv = Instance.new("BodyVelocity")
        bv.Velocity = hrp.CFrame.LookVector * 15
        bv.MaxForce = Vector3.new(4000,4000,4000)
        bv.Parent = ball
        Debris:AddItem(bv,0.2)
    end
    updateLabel(spawnedLabel)
end

local function deleteAllBalls()
    for _, ball in pairs(spawnedBalls) do
        if ball and ball.Parent then ball:Destroy() end
    end
    spawnedBalls = {}
    updateLabel(spawnedLabel)
end

local function deleteAmountBalls(amount)
    for i = 1, amount do
        local ball = table.remove(spawnedBalls)
        if ball and ball.Parent then ball:Destroy() end
    end
    updateLabel(spawnedLabel)
end

local function emergencyRecovery()
    local hrp = getHRP()
    for _, ball in pairs(spawnedBalls) do
        if ball and ball.Parent then
            ball.Position = hrp.Position + hrp.CFrame.LookVector * 5
        end
    end
end

-- Input Handlers for Grabbing
local function onInputBegan(input)
    if grabbableMode and input.UserInputType ~= Enum.UserInputType.Keyboard then
        local mousePos = input.Position
        local closest, minDist = nil, math.huge
        for _, ball in pairs(spawnedBalls) do
            if ball and ball.Parent then
                local screenPos, onScreen = workspace.CurrentCamera:WorldToScreenPoint(ball.Position)
                if onScreen then
                    local dist = (Vector2.new(screenPos.X, screenPos.Y) - Vector2.new(mousePos.X, mousePos.Y)).Magnitude
                    if dist < minDist and dist < 50 then
                        closest = ball
                        minDist = dist
                    end
                end
            end
        end
        if closest then
            grabbedBall = closest
            local ray = workspace.CurrentCamera:ScreenPointToRay(mousePos.X, mousePos.Y)
            grabOffset = closest.Position - ray.Origin
        end
    end
end

local function onInputChanged(input)
    if grabbedBall then
        local ray = workspace.CurrentCamera:ScreenPointToRay(input.Position.X,input.Position.Y)
        grabbedBall.Position = ray.Origin + grabOffset
    end
end

local function onInputEnded(input)
    grabbedBall = nil
end

-- Fun UI
local funGui
local function openFunUI()
    if funGui then funGui:Destroy() end
    if activeFunConnection then activeFunConnection:Disconnect() activeFunConnection = nil end
    funGui = Instance.new("Frame")
    funGui.Size = UDim2.new(0,220,0,250)
    funGui.Position = UDim2.new(0,50,0,50)
    funGui.BackgroundColor3 = Color3.fromRGB(80,80,80)
    funGui.Parent = screenGui
    makeDraggable(funGui)

    -- Title
    local fTitle = Instance.new("TextLabel")
    fTitle.Size = UDim2.new(1,0,0,30)
    fTitle.BackgroundTransparency = 1
    fTitle.Text = "Fun Menu"
    fTitle.TextColor3 = Color3.new(1,1,1)
    fTitle.TextScaled = true
    fTitle.Parent = funGui

    -- X button
    local fxButton = Instance.new("TextButton")
    fxButton.Size = UDim2.new(0,30,0,30)
    fxButton.Position = UDim2.new(1,-35,0,5)
    fxButton.Text = "X"
    fxButton.TextScaled = true
    fxButton.BackgroundColor3 = Color3.fromRGB(170,0,0)
    fxButton.Parent = funGui
    fxButton.MouseButton1Click:Connect(function()
        if activeFunConnection then activeFunConnection:Disconnect() activeFunConnection=nil end
        funGui:Destroy()
    end)

    -- Cancel Button
    local cancelButton = Instance.new("TextButton")
    cancelButton.Size = UDim2.new(0,180,0,30)
    cancelButton.Position = UDim2.new(0,20,0,210)
    cancelButton.Text = "Cancel Current Action"
    cancelButton.TextScaled = true
    cancelButton.BackgroundColor3 = Color3.fromRGB(255,0,255)
    cancelButton.Parent = funGui
    cancelButton.MouseButton1Click:Connect(function()
        if activeFunConnection then activeFunConnection:Disconnect() activeFunConnection=nil end
    end)

    -- Fun Buttons
    local funOptions = {
        {Name="Float Around Head", Func=function()
            local hrp = getHRP()
            local radius = 5
            local angle = 0
            if activeFunConnection then activeFunConnection:Disconnect() end
            activeFunConnection = RunService.Heartbeat:Connect(function(dt)
                angle = angle + dt*2
                for i, ball in pairs(spawnedBalls) do
                    if ball and ball.Parent then
                        local offset = Vector3.new(math.cos(angle+i)*radius,3,math.sin(angle+i)*radius)
                        ball.CFrame = CFrame.new(hrp.Position + offset)
                    end
                end
            end)
        end},
        {Name="Orbit Horizontally", Func=function()
            local hrp = getHRP()
            local radius = 5
            local angle = 0
            if activeFunConnection then activeFunConnection:Disconnect() end
            activeFunConnection = RunService.Heartbeat:Connect(function(dt)
                angle = angle + dt*3
                for i, ball in pairs(spawnedBalls) do
                    if ball and ball.Parent then
                        local offset = Vector3.new(math.cos(angle+i)*radius, 2 + math.sin(angle*2+i), math.sin(angle+i)*radius)
                        ball.CFrame = CFrame.new(hrp.Position + offset)
                    end
                end
            end)
        end},
        {Name="Bounce Up and Down", Func=function()
            if activeFunConnection then activeFunConnection:Disconnect() end
            local t = 0
            activeFunConnection = RunService.Heartbeat:Connect(function(dt)
                t = t + dt*4
                for i, ball in pairs(spawnedBalls) do
                    if ball and ball.Parent then
                        local pos = ball.Position
                        ball.Position = Vector3.new(pos.X, 2 + math.sin(t+i), pos.Z)
                    end
                end
            end)
        end},
        {Name="Random Fireworks", Func=function()
            if activeFunConnection then activeFunConnection:Disconnect() end
            local t = 0
            activeFunConnection = RunService.Heartbeat:Connect(function(dt)
                t = t + dt
                for i, ball in pairs(spawnedBalls) do
                    if ball and ball.Parent then
                        ball.Position = Vector3.new(math.random(-20,20), math.random(5,15), math.random(-20,20))
                    end
                end
            end)
        end}
    }

    for i,opt in pairs(funOptions) do
        local btn = Instance.new("TextButton")
        btn.Size = UDim2.new(0,180,0,30)
        btn.Position = UDim2.new(0,20,0,40+40*(i-1))
        btn.Text = opt.Name
        btn.TextScaled = true
        btn.BackgroundColor3 = Color3.fromRGB(100,255,100)
        btn.Parent = funGui
        btn.MouseButton1Click:Connect(opt.Func)
    end
end

-- Connections
spawnButton.MouseButton1Click:Connect(function()
    local amt = tonumber(amountBox.Text) or 1
    spawnBalls(amt)
end)
deleteAllButton.MouseButton1Click:Connect(deleteAllBalls)
deleteAmountButton.MouseButton1Click:Connect(function()
    local amt = tonumber(amountBox.Text) or 1
    deleteAmountBalls(amt)
end)
emergencyButton.MouseButton1Click:Connect(emergencyRecovery)
xButton.MouseButton1Click:Connect(function()
    deleteAllBalls()
    if activeFunConnection then activeFunConnection:Disconnect() activeFunConnection=nil end
    screenGui:Destroy()
end)
grabbableButton.MouseButton1Click:Connect(function()
    grabbableMode = not grabbableMode
    grabbableButton.Text = "Toggle Grabbable Balls: "..(grabbableMode and "ON" or "OFF")
end)
funButton.MouseButton1Click:Connect(openFunUI)

-- Input Handlers
UserInputService.InputBegan:Connect(function(input)
    onInputBegan(input)
end)
UserInputService.InputChanged:Connect(function(input)
    onInputChanged(input)
end)
UserInputService.InputEnded:Connect(function(input)
    onInputEnded(input)
end)

-- Handle character respawn
player.CharacterAdded:Connect(function()
    RunService.Heartbeat:Wait()
    emergencyRecovery()
end)

Features & Information

A client-side script that allows you to spawn as many tiny balls you want & delete all or a certain amount. Mobile supported. And also it allows you to do fun things with the balls (eg, orbiting you, bouncing etc).
#fun#universal#clientside

Community Comments (1)

VerygoodusernameVerygoodusernameSep 8, 2025

Can you make them kick able so i can play football with myself

More Scripts for Universal Scripts