How can I make a ball system like this

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    A ball physics system

  2. What is the issue? Include screenshots / videos if possible!

I want to make my ball have physics like this

  1. What solutions have you tried so far? Did you look for solutions on the Creator Hub?

I tried looking for solutions but could not find anything

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

here is my current server script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local PhysicsService = game:GetService("PhysicsService")

local Settings = require(ReplicatedStorage:WaitForChild("Settings"))
local Events = ReplicatedStorage:WaitForChild("Events")
local remoteKick = Events:WaitForChild("KickEvent")
local WeldBall = Events:WaitForChild("WeldBall")

local ball = script.Parent

local BALL_GROUP = "Ball"
local PLAYER_GROUP = "Player"

pcall(function() PhysicsService:RegisterCollisionGroup(BALL_GROUP) end)
pcall(function() PhysicsService:RegisterCollisionGroup(PLAYER_GROUP) end)
PhysicsService:CollisionGroupSetCollidable(BALL_GROUP, PLAYER_GROUP, false)

ball.CollisionGroup = BALL_GROUP
if ball:FindFirstChild("SoccerBall") then
	ball.SoccerBall.CollisionGroup = BALL_GROUP
end

local ballDrag = 2.5
local kickPowerMin = 1
local kickPowerMax = 80
local kickPowerDiff = kickPowerMax - kickPowerMin

local dragBodyForce = ball:FindFirstChildOfClass("BodyForce") or Instance.new("BodyForce")
dragBodyForce.Parent = ball


local weldedToPlayer = {}
local currentOwner = nil
local weld
local inCurve = false

local function removeWeld()
	if weld then
		weld:Destroy()
		weld = nil
		ball.Parent = workspace
	end
end

local function stopSpinning()
	ball.AssemblyAngularVelocity = Vector3.new(0, 0, 0)
	for _, child in ipairs(ball:GetChildren()) do
		if child:IsA("BodyGyro") or child:IsA("BodyAngularVelocity") then
			child:Destroy()
		end
	end
end

local function applyDrag()
	if inCurve then
		dragBodyForce.Force = Vector3.new(0,0,0)
		return
	end
	local velocity = ball.AssemblyLinearVelocity
	local dragForceValue = velocity * -ballDrag
	dragBodyForce.Force = dragForceValue + Vector3.new(0, -workspace.Gravity * ball.AssemblyMass, 0)
end

local function hasBall(player)
	return player:GetAttribute("HasBall") == true
end

local function isNearBall(player, ballPart, radius)
	local character = player.Character
	if not character then return false end
	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if not rootPart then return false end
	return (rootPart.Position - ballPart.Position).Magnitude <= radius
end

local function assignCollisionGroup(character)
	for _, part in ipairs(character:GetDescendants()) do
		if part:IsA("BasePart") then
			part.CollisionGroup = PLAYER_GROUP
		end
	end
end

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		task.wait(0.1)
		assignCollisionGroup(character)
	end)
end)

-- SORRY FOR THIS CODE BEING TRASH

local function weldBallFunc(player)
	if hasBall(player) then return end
	if not isNearBall(player, ball, 12) then return end
	if currentOwner and Players:IsAncestorOf(currentOwner) then
		currentOwner:SetAttribute("HasBall", false)
	end
	currentOwner = player
	player:SetAttribute("HasBall", true)
	local character = player.Character
	if not character then return false end
	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if not rootPart then return false end
	ball.Parent = character
	ball:SetNetworkOwner(player)
	ball.Massless = true
	ball.CanTouch = false
	ball.CanCollide = false
	ball.CollisionGroup = BALL_GROUP
	if weld then weld:Destroy() end
	weld = Instance.new("Motor6D")
	weld.Name = "BallMotor"
	weld.Part0 = rootPart
	weld.Part1 = ball
	weld.Parent = ball
	weld.C0 = CFrame.new(0, -2, -2.5)
	weldedToPlayer[ball] = player.UserId
end

local function quadBezier(t, p0, p1, p2)
	return (1 - t) * (1 - t) * p0 + 2 * (1 - t) * t * p1 + t * t * p2
end

local function CreateCurvePoints(p0, p1, p2, steps)
	local points = {}
	for i = 0, steps do
		local t = i / steps
		points[#points+1] = quadBezier(t, p0, p1, p2)
	end
	return points
end

local activeCurveConn

local function BallMotion(p0, p1, p2, targetBall)
	local steps = 60
	local points = CreateCurvePoints(p0, p1, p2, steps)
	if #points < 2 then return end

	local dt = 1/60
	local initialVel = (points[2] - points[1]) / dt

	targetBall.Anchored = false
	targetBall.CanCollide = true
	targetBall.AssemblyLinearVelocity = initialVel
end


remoteKick.OnServerEvent:Connect(function(player, cameraDirection, powerValue)
	if not weldedToPlayer[ball] or weldedToPlayer[ball] ~= player.UserId then
		return
	end
	removeWeld()
	player:SetAttribute("HasBall", false)
	stopSpinning()
	ball.CanTouch = false
	ball.Massless = false
	ball.CollisionGroup = BALL_GROUP

	local character = player.Character
	local rootpart = character and character:FindFirstChild("HumanoidRootPart")
	if not rootpart then
		ball.CanTouch = true
		return
	end

	local dir = (cameraDirection and cameraDirection.Unit) or rootpart.CFrame.LookVector
	local p = math.clamp(tonumber(powerValue) or 0, 0, 1)
	
	local minDist = 12
	local maxDist = 40
	local dist = minDist + (maxDist - minDist) * p

	local arcHMin = 6
	local arcHMax = 16
	local arcH = arcHMin + (arcHMax - arcHMin) * p

	local startPos = ball.Position
	local dir = cameraDirection.Unit
	local p = math.clamp(powerValue, 0, 1)

	local dist = Settings.MinDist + (Settings.MaxDist - Settings.MinDist) * p
	local height = Settings.MinHeight + (Settings.MaxHeight - Settings.MinHeight) * p


	local p0 = startPos
	local p1 = startPos + dir * (dist * 0.5) + Vector3.new(0, height, 0)
	local p2 = startPos + dir * dist

	BallMotion(p0, p1, p2, ball)

	task.delay(0.25, function()
		ball.CanTouch = true
	end)
end)

WeldBall.OnServerEvent:Connect(weldBallFunc)

RunService.Heartbeat:Connect(function()
	if ball.Parent == workspace then
		applyDrag()
	else
		dragBodyForce.Force = Vector3.new(0,0,0)
	end
end)

RunService.Stepped:Connect(function()
	if weld and ball.Parent == workspace then
		local character = weld.Part1 and weld.Part1.Parent
		if not (character and character:FindFirstChild("Humanoid")) then
			local player = Players:GetPlayerFromCharacter(character)
			if player then
				player:SetAttribute("HasBall", false)
				removeWeld()
				ball.Massless = false
				ball.CanCollide = true
				ball.CollisionGroup = BALL_GROUP
			end
		end
	else
		stopSpinning()
	end
end)