So i actually did something similar with my basketball tool
local Tool = script.Parent
local Handle = Tool:WaitForChild(“Handle”) – Assuming the ball mesh is named Handle
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
local RunService = game:GetService(“RunService”)
local Workspace = game.Workspace
– Constants
local GRAVITY = Vector3.new(0, -196.2, 0) – Gravity in studs/s²
local TRAJECTORY_RESOLUTION = 50 – Number of points on the curve
local THROW_FORCE = 100 – Initial velocity multiplier
– Variables
local isHolding = false
local trajectoryPoints = {}
local beam = nil
local attachment0 = nil
local attachment1 = nil
– Helper: Create a beam for trajectory visualization
local function setupBeam()
if not beam then
attachment0 = Instance.new(“Attachment”)
attachment1 = Instance.new(“Attachment”)
attachment0.Parent = Handle
attachment1.Parent = Workspace.Terrain -- Temporary parent; will be positioned dynamically
beam = Instance.new("Beam")
beam.Attachment0 = attachment0
beam.Attachment1 = attachment1
beam.Color = ColorSequence.new(Color3.new(1, 1, 0)) -- Yellow
beam.Width0 = 0.1
beam.Width1 = 0.1
beam.CurveSize0 = 0.5
beam.CurveSize1 = 0.5
beam.Parent = Handle
end
end
– Predict trajectory and generate curve points
local function calculateTrajectory(startPosition, initialVelocity, resolution)
local points = {}
local timeStep = 0.05
for i = 1, resolution do
local t = timeStep * i
local position = startPosition + (initialVelocity * t) + (0.5 * GRAVITY * t * t)
table.insert(points, position)
-- Check for collision with ground
local ray = Ray.new(points[i - 1] or startPosition, (position - (points[i - 1] or startPosition)).Unit * 10)
local hit, hitPosition = Workspace:FindPartOnRay(ray)
if hit then
-- Stop calculation at the point of collision
for j = #points, resolution do
table.remove(points, j) -- Remove excess points
end
table.insert(points, hitPosition) -- Add the landing point
break
end
end
return points
end
– Render trajectory visualization using Bezier approximation
local function renderTrajectory(points)
if #points < 2 then return end
-- Use the first, middle, and last points to approximate a curve
local startPosition = points[1]
local midPosition = points[math.floor(#points / 2)]
local endPosition = points[#points]
-- Update beam attachments
attachment0.WorldPosition = startPosition
attachment1.WorldPosition = endPosition
-- Curve details
beam.CurveSize0 = (midPosition - startPosition).Magnitude * 0.5
beam.CurveSize1 = (endPosition - midPosition).Magnitude * 0.5
end
– Throw the ball
local function throwBall(landingPosition)
local newBall = Handle:Clone()
newBall.Parent = Workspace
newBall.Position = Handle.Position
local velocity = (landingPosition - newBall.Position).Unit * THROW_FORCE
local bodyVelocity = Instance.new("BodyVelocity")
bodyVelocity.Velocity = velocity
bodyVelocity.MaxForce = Vector3.new(1e6, 1e6, 1e6)
bodyVelocity.Parent = newBall
-- Cleanup after 5 seconds
game:GetService("Debris"):AddItem(newBall, 5)
end
– Mouse button down
Mouse.Button1Down:Connect(function()
isHolding = true
setupBeam()
-- Predict trajectory while holding
RunService.RenderStepped:Connect(function()
if isHolding then
local startPosition = Handle.Position
if Mouse.Hit then
local targetPosition = Mouse.Hit.Position
local velocity = (targetPosition - startPosition).Unit * THROW_FORCE
trajectoryPoints = calculateTrajectory(startPosition, velocity, TRAJECTORY_RESOLUTION)
renderTrajectory(trajectoryPoints)
end
end
end)
end)
– Mouse button up
Mouse.Button1Up:Connect(function()
isHolding = false
-- Throw the ball
if #trajectoryPoints > 0 then
local landingPosition = trajectoryPoints[#trajectoryPoints]
throwBall(landingPosition)
end
-- Clear trajectory visualization
if beam then
beam:Destroy()
beam = nil
end
if attachment0 then attachment0:Destroy() end
if attachment1 then attachment1:Destroy() end
end)