You can write your topic however you want, but you need to answer these questions:
-
What do you want to achieve? Keep it simple and clear!
A ball physics system -
What is the issue? Include screenshots / videos if possible!
I want to make my ball have physics like this
- 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)