I want it so that when the ball reaches “Spot” for it to stop moving and just be there.
The issue is that the ball starts spinning around and glitching after it reaches the spot. It’s moving it to the CFrame of the Spot.
At first I tried to keep the ball up there by constantly teleporting it to the Spot’s position but that was weird so I removed it. The idea I got was to bring the ball to the Spot and then anchor the ball once it has reached the spot. But for some reason. It gets anchored and I don’t think it’s constantly being held or teleported for it to get that weird spinning and glitching effect. So can somebody please help me out?
local magnet = script.Parent – The hitbox part
local ballsFolder = workspace:WaitForChild(“Balls”)
local TweenService = game:GetService(“TweenService”)
local Debris = game:GetService(“Debris”)
– Configuration parameters
local tweenDuration = 1 – Seconds for the smooth transfer (tween)
local launchCooldown = 5 – Seconds before the magnet can affect this ball again
local launchSpeed = 30 – Horizontal launch impulse (studs/sec)
– Get the Spot part (should be in the same model as the hitbox, but not inside it)
local model = magnet.Parent
local spot = model:FindFirstChild(“Spot”)
if not spot then
warn(“Spot part not found in the model!”)
return
end
– Tables to track state for each ball
local cooldownBalls = {} – ballModel → cooldown expiration time
local heldBalls = {} – ballModel → { tween, launchConn, toggleEvent, player }
– Helper: Given a part, find its ball model (first ancestor whose parent is workspace.Balls)
local function getBallModel(part)
local current = part:FindFirstAncestorWhichIsA(“Model”)
while current and current.Parent and current.Parent ~= ballsFolder do
current = current.Parent
end
return current
end
local function holdBall(ballModel)
if cooldownBalls[ballModel] and tick() < cooldownBalls[ballModel] then
return – Ball is still on cooldown
end
if heldBalls[ballModel] then
return – Already processing this ball
end
-- Always set the PrimaryPart to the CollisionBall from ball.Exterior.
local exterior = ballModel:FindFirstChild("Exterior")
if exterior then
local collisionBall = exterior:FindFirstChild("CollisionBall")
if collisionBall then
ballModel.PrimaryPart = collisionBall
end
end
if not ballModel.PrimaryPart then
warn("Ball model " .. ballModel.Name .. " has no PrimaryPart (CollisionBall).")
return
end
-- Get required RemoteEvents and the owning player.
local eventsFolder = ballModel:FindFirstChild("Events")
local toggleEvent = eventsFolder and eventsFolder:FindFirstChild("ToggleInputControlsRemoteEvent")
local launchEvent = eventsFolder and eventsFolder:FindFirstChild("LaunchBallRemoteEvent")
local playerValue = ballModel:FindFirstChild("Player")
local player = (playerValue and playerValue.Value) or nil
-- Disable the ball's own input controls so its movement doesn't interfere.
if toggleEvent and player then
toggleEvent:FireClient(player, false)
end
local part = ballModel.PrimaryPart
part.Anchored = true -- Anchor to take full control of movement
-- Create a tween to smoothly move the ball (including upward) to the Spot.
local tweenInfo = TweenInfo.new(tweenDuration, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
local tweenGoal = { CFrame = spot.CFrame }
local tween = TweenService:Create(part, tweenInfo, tweenGoal)
heldBalls[ballModel] = {
tween = tween,
launchConn = nil,
toggleEvent = toggleEvent,
player = player,
}
tween:Play()
tween.Completed:Connect(function()
-- Once the tween completes, explicitly set the ball exactly at Spot and anchor it.
part.CFrame = spot.CFrame
part.Anchored = true
print("DEBUG: Ball " .. ballModel.Name .. " reached the spot and is now anchored.")
end)
-- Listen for the launch event from the client.
if launchEvent and player then
local conn
conn = launchEvent.OnServerEvent:Connect(function(plr)
if plr == player and heldBalls[ballModel] then
if conn then conn:Disconnect() end
-- Unanchor the ball and apply a horizontal impulse.
part.Anchored = false
local forward = part.CFrame.LookVector
forward = Vector3.new(forward.X, 0, forward.Z).Unit
local bv = Instance.new("BodyVelocity")
bv.Name = "LaunchImpulse"
bv.MaxForce = Vector3.new(1e5, 0, 1e5) -- Only affect horizontal motion.
bv.Velocity = forward * launchSpeed
bv.Parent = part
Debris:AddItem(bv, 0.1)
-- Re-enable the ball's input controls.
if toggleEvent and player then
toggleEvent:FireClient(player, true)
end
heldBalls[ballModel] = nil
cooldownBalls[ballModel] = tick() + launchCooldown
end
end)
heldBalls[ballModel].launchConn = conn
end
end
local function onTouched(otherPart)
local ballModel = getBallModel(otherPart)
if ballModel and ballModel:IsDescendantOf(ballsFolder) then
holdBall(ballModel)
end
end
magnet.Touched:Connect(onTouched)