Long story short, I’ve been trying to fix this bug with my roblox soccer ball/football for the past 2 hours or so, and I just cannot get it to work. It must be a very simple fix but I just can’t figure it out.
The issue I am facing is that the ball keeps teleporting back and then continues rolling. This only occurs after it has been kicked multiple times, and it sort of ‘builds up’. It gets worse every time.
Video:
Script:
local cooldown = 0.2
local lastShot = 0
local friction = 0.985
local spinFriction = 0.98
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = {workspace}
local function resetBall()
local ball = script.Parent
ball.CanCollide = true
ball.Anchored = false
ball.CanTouch = true
ball.Massless = false
ball.AssemblyLinearVelocity = Vector3.zero
ball.AssemblyAngularVelocity = Vector3.zero
ball.Velocity = Vector3.zero
ball.RotVelocity = Vector3.zero
ball.Position = ball.Position + Vector3.new(0, 0.01, 0)
ball.Orientation = Vector3.zero
task.wait(0.002)
end
local function applyFriction()
while true do
local ball = script.Parent
local velocity = ball.AssemblyLinearVelocity
local angularVelocity = ball.AssemblyAngularVelocity
local touching = ball:GetTouchingParts()
local onGround = false
for _, part in ipairs(touching) do
if part.Name == "Grass" then
onGround = true
break
end
end
if onGround then
ball.AssemblyLinearVelocity *= friction
ball.AssemblyAngularVelocity *= spinFriction
if velocity.Magnitude < 0.05 then
ball.AssemblyLinearVelocity = Vector3.zero
end
if angularVelocity.Magnitude < 0.05 then
ball.AssemblyAngularVelocity = Vector3.zero
end
end
task.wait(0.03)
end
end
task.spawn(applyFriction)
local function shoot(force, lift, player, rawPower)
resetBall()
task.wait(0.005)
local ball = script.Parent
local direction = player.HumanoidRootPart.CFrame.LookVector
local finalForce = (direction * force) + Vector3.new(0, lift, 0)
ball.AssemblyLinearVelocity = finalForce
ball.AssemblyAngularVelocity = Vector3.zero
if rawPower > 75 then
ball.Shoot:Play()
else
ball.Kick:Play()
end
task.wait(1)
ball.CurrentOwner.Value = nil
end
game:GetService("ReplicatedStorage").Events.Shoot.OnServerEvent:Connect(function(player, power, height)
local character = player.Character
if not character then return end
local hitbox = character:FindFirstChild("FeetHitbox")
if not hitbox then return end
if tick() - lastShot < cooldown then
print("shot blocked")
return
end
lastShot = tick()
script.Parent.CanTouch = true
script.Parent.Massless = false
local waitTime = 0.425
local start = tick()
local confirmed = false
while tick() - start < waitTime do
local ballPos = script.Parent.Position
local hitboxPos = hitbox.Position
local ballSize = script.Parent.Size / 2
local hitboxSize = hitbox.Size / 2
local touching =
math.abs(ballPos.X - hitboxPos.X) <= (hitboxSize.X + ballSize.X) and
math.abs(ballPos.Y - hitboxPos.Y) <= (hitboxSize.Y + ballSize.Y) and
math.abs(ballPos.Z - hitboxPos.Z) <= (hitboxSize.Z + ballSize.Z)
for _, part in ipairs(script.Parent:GetTouchingParts()) do
if part:IsDescendantOf(hitbox.Parent) then
touching = true
break
end
end
if touching then
local clampedPower = math.clamp(power, 25, 100)
local adjustedPower = math.clamp(clampedPower / 100 * 150, 20, 150)
local adjustedHeight = (height / 100 * 60) * clampedPower / 100
print("height: " .. tostring(height) .. " adjusted: " .. tostring(adjustedHeight))
script.Parent.LastOwner.Value = player
resetBall()
shoot(adjustedPower, adjustedHeight, character, clampedPower)
confirmed = true
break
end
task.wait(0.05)
end
if not confirmed then
print("no shot")
end
end)