CCCPaste

8 BALL POOL

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
}