Off-Screen Indicator Help

Hello, thank you for assisting me in my troubles. In my local script located in StarterCharacterScripts, I have this custom camera system that shows an indicator of an NPC or player when their avatar goes off the local player’s screen. The only catch is that when the non-local player goes under the local player’s viewpoint and walks a certain distance, their indicator will gradually rise for some odd reason.

I’d appreciate it if you could help me as I spent a lot of time working on this script, only for it to not turn out the way that I liked it.

Script:

local function updateIndicators()
    for target, indicator in pairs(indicators) do
        local character = target:IsA("Player") and target.Character or target
        local hrp = character and character:FindFirstChild("HumanoidRootPart")

        if not hrp then
            indicator.Visible = false
            continue
        end

        local viewportSize = cam.ViewportSize
        local screenCenter = Vector2.new(viewportSize.X / 2, viewportSize.Y / 2)
        local screenPoint, onScreen = cam:WorldToViewportPoint(hrp.Position)

        -- If the target is on screen and in front of the camera, hide the indicator
        if onScreen and screenPoint.Z > 0 then
            indicator.Visible = false
            continue
        end

        -- Calculate the distance from the local player to the target player
        local distanceFromPlayer = (player.Character.HumanoidRootPart.Position - hrp.Position).Magnitude

        -- Smoothly raise the indicator's position if the target is too far away
        local moveThreshold = 100  -- Adjusted this threshold as needed
        local upwardOffset = 0

        if distanceFromPlayer > moveThreshold then
            upwardOffset = math.min((distanceFromPlayer - moveThreshold) / 0.5, 0)  -- Clamped upwardOffset
        end

        local toTarget = (hrp.Position - cam.CFrame.Position).Unit
        local forward = cam.CFrame.LookVector
        local dotProduct = forward:Dot(toTarget)

        if dotProduct < 0 then
            screenPoint = Vector3.new(-screenPoint.X, -screenPoint.Y, 0)
        end

        local direction = (Vector2.new(screenPoint.X, screenPoint.Y) - screenCenter).Unit
        local edgeOffset = 50  -- Adjusted for better visual appearance
        local maxX, maxY = viewportSize.X - edgeOffset, viewportSize.Y - edgeOffset

        local slope = direction.Y / direction.X
        local edgeX, edgeY = screenCenter.X, screenCenter.Y

        if math.abs(slope) > viewportSize.Y / viewportSize.X then
            edgeY = direction.Y > 0 and maxY or edgeOffset
            edgeX = screenCenter.X + (edgeY - screenCenter.Y) / slope
        else
            edgeX = direction.X > 0 and maxX or edgeOffset
            edgeY = screenCenter.Y + (edgeX - screenCenter.X) * slope
        end

        edgeX = math.clamp(edgeX, edgeOffset, maxX)
        edgeY = math.clamp(edgeY + upwardOffset, edgeOffset, maxY) -- Adjust Y position with upwardOffset

        local tweenInfo = TweenInfo.new(0.15, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
        local tween = tweenService:Create(indicator, tweenInfo, {Position = UDim2.new(0, edgeX, 0, edgeY)})
        tween:Play()

        indicator.Rotation = math.deg(math.atan2(direction.Y, direction.X)) + 90
        indicator.Visible = true
    end
end
1 Like

I’m still looking for assistance.