local Table1 = workspace.Tables.Table1 local HitTrajectory = Table1.Guides.HitTrajectory -- Enhanced configuration local config = { maxSegments = 8, segmentLength = 6, maxBounces = 3, ballRadius = 1.2, -- Approximate ball radius for collision powerMultiplier = 1.5, -- Adjust trajectory length based on power fadeIntensity = true, -- Whether segments fade with distance showBouncePoints = true -- Show markers where trajectory bounces } local trajectoryParts = {} local bounceMarkers = {} local currentPower = 1.0 -- Material colors for visual appeal local colors = { primary = BrickColor.new("Bright green"), secondary = BrickColor.new("Bright blue"), bounce = BrickColor.new("Bright yellow"), fade = BrickColor.new("Dark green") } -- Physics constants local BALL_MASS = 1.0 local FRICTION = 0.98 local MIN_VELOCITY = 0.1 -- Create a better looking trajectory segment local function createTrajectorySegment(position, direction, length, alpha, isBounce) local part = Instance.new("Part") part.Size = Vector3.new(0.15, 0.15, length) part.CFrame = CFrame.lookAt(position, position + direction) * CFrame.new(0, 0, -length / 2) part.Anchored = true part.CanCollide = false part.CastShadow = false -- Visual customization local material = isBounce and Enum.Material.Neon or Enum.Material.SmoothPlastic part.Material = material local color = isBounce and colors.bounce or colors.primary if config.fadeIntensity then -- Blend towards fade color based on alpha local lerpValue = 1 - alpha part.BrickColor = color:lerp(colors.fade, lerpValue) else part.BrickColor = color end part.Transparency = isBounce and 0.2 or alpha * 0.5 part.Parent = workspace return part end -- Create bounce marker local function createBounceMarker(position) if not config.showBouncePoints then return end local marker = Instance.new("Part") marker.Size = Vector3.new(0.8, 0.8, 0.8) marker.Shape = Enum.PartType.Ball marker.CFrame = CFrame.new(position) marker.BrickColor = colors.bounce marker.Material = Enum.Material.Neon marker.Anchored = true marker.CanCollide = false marker.Transparency = 0.3 marker.Parent = workspace return marker end -- Clear all trajectory visuals local function clearTrajectory() for _, part in pairs(trajectoryParts) do if part and part.Parent then part:Destroy() end end trajectoryParts = {} for _, marker in pairs(bounceMarkers) do if marker and marker.Parent then marker:Destroy() end end bounceMarkers = {} end -- Raycast with ball collision detection local function raycastWithBallCollision(startPos, direction, ignoreList) local params = RaycastParams.new() params.FilterType = Enum.RaycastFilterType.Blacklist params.FilterDescendantsInstances = ignoreList or {} params.IgnoreWater = true local ray = workspace:Raycast(startPos, direction * config.segmentLength, params) if ray then -- Check if we hit a ball (approximate by size and name) local hit = ray.Instance if hit and (hit.Name:lower():find("ball") or hit.Size.Magnitude < 3) then -- Calculate reflection for ball collision (simplified) local normal = (ray.Position - hit.Position).Unit local reflection = direction - 2 * direction:Dot(normal) * normal return ray.Position, reflection, true, hit else -- Standard wall collision local reflection = direction - 2 * direction:Dot(ray.Normal) * ray.Normal return ray.Position, reflection, false, hit end end return startPos + direction * config.segmentLength, direction, false, nil end -- Calculate cue ball physics local function calculateBallPhysics(startPos, direction, power) local velocity = direction * power * config.powerMultiplier local positions = {} local bounces = 0 local currentPos = startPos local currentVel = velocity for i = 1, config.maxSegments do if bounces >= config.maxBounces then break end -- Apply friction currentVel = currentVel * FRICTION -- Stop if velocity is too low if currentVel.Magnitude < MIN_VELOCITY then break end local nextPos, newDirection, didBounce, hitObject = raycastWithBallCollision( currentPos, currentVel.Unit, {workspace.Tables.Table1} -- Ignore table parts ) -- Calculate segment length local segmentLength = (nextPos - currentPos).Magnitude -- Create trajectory segment with fade effect local alpha = (i - 1) / config.maxSegments local segment = createTrajectorySegment(currentPos, currentVel.Unit, segmentLength, alpha, didBounce) table.insert(trajectoryParts, segment) if didBounce then bounces = bounces + 1 if config.showBouncePoints then local marker = createBounceMarker(nextPos) table.insert(bounceMarkers, marker) end -- If we hit a ball, we might want to stop or change trajectory significantly if hitObject and hitObject.Name:lower():find("ball") then -- For ball hits, we could add special effects or stop the trajectory currentVel = currentVel * 0.7 -- Reduce velocity after ball collision end end currentPos = nextPos currentVel = newDirection * currentVel.Magnitude table.insert(positions, currentPos) end return positions end -- Main trajectory update function local function updateTrajectory() clearTrajectory() local startPos = HitTrajectory.Position local direction = HitTrajectory.CFrame.LookVector.Unit -- Calculate trajectory with physics calculateBallPhysics(startPos, direction, currentPower) end -- Power control functions local function setPower(power) currentPower = math.clamp(power, 0.1, 2.0) updateTrajectory() end local function increasePower() setPower(currentPower + 0.1) end local function decreasePower() setPower(currentPower - 0.1) end -- Connect events HitTrajectory:GetPropertyChangedSignal("CFrame"):Connect(updateTrajectory) -- Optional: Add power control bindings (uncomment if you want keyboard controls) -- game:GetService("UserInputService").InputBegan:Connect(function(input) -- if input.KeyCode == Enum.KeyCode.E then -- increasePower() -- elseif input.KeyCode == Enum.KeyCode.Q then -- decreasePower() -- end -- end) -- Initialize updateTrajectory() -- Return API for external control return { updateTrajectory = updateTrajectory, setPower = setPower, increasePower = increasePower, decreasePower = decreasePower, clearTrajectory = clearTrajectory, getCurrentPower = function() return currentPower end }