--!optimize 2 --!native -- // Services local Players = game:GetService("Players") local RunService = game:GetService("RunService") local CoreGui = game:GetService("CoreGui") -- Alternative parent for Highlight if needed -- // Local Player Variables local LocalPlayer = Players.LocalPlayer local PlayerGui = LocalPlayer:WaitForChild("PlayerGui") -- Ensure PlayerGui is loaded -- // Configuration local ESP_ENABLED = true -- Toggle the entire ESP on/off local TEAM_CHECK_ENABLED = true -- << NEW: Only show ESP for players NOT on your team local SHOW_NAMES = true local SHOW_HEALTH = true local USE_HIGHLIGHT = true -- Use the Highlight instance for outlines local HIGHLIGHT_COLOR = Color3.fromRGB(255, 50, 50) -- Red for enemies (adjust as needed) local HIGHLIGHT_FILL_TRANSPARENCY = 0.8 local NAME_COLOR = Color3.fromRGB(255, 255, 255) -- White name local HEALTH_BAR_ENABLED = true -- Simple bar above health text local HEALTH_BAR_SIZE = UDim2.new(0, 100, 0, 5) -- Width 100px, Height 5px local MAX_DISTANCE = 1000 -- Only show ESP for players within this distance (in studs). Set to math.huge for infinite. -- // ESP Management Table local espInstances = {} -- Store references to created ESP elements { Player = { BillboardGui, Highlight } } -- // Function to clean up ESP for a specific player local function CleanupESP(targetPlayer) if espInstances[targetPlayer] then if espInstances[targetPlayer].BillboardGui then espInstances[targetPlayer].BillboardGui:Destroy() end if espInstances[targetPlayer].Highlight then espInstances[targetPlayer].Highlight:Destroy() end espInstances[targetPlayer] = nil -- Remove entry end end -- // Function to create or update ESP for a target player local function UpdateESP(targetPlayer) if not ESP_ENABLED then return -- Exit if ESP is globally disabled end local character = targetPlayer.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") local head = character and character:FindFirstChild("Head") local hrp = character and character:FindFirstChild("HumanoidRootPart") -- For distance check -- // --- Validation Checks --- if not character or not humanoid or humanoid.Health <= 0 or not head or not hrp then CleanupESP(targetPlayer) -- Cleanup if character/humanoid is invalid or dead return -- Stop processing this player end -- // --- Team Check --- if TEAM_CHECK_ENABLED then local localTeam = LocalPlayer.Team local targetTeam = targetPlayer.Team -- Only hide if both players HAVE a team and the teams ARE THE SAME if localTeam and targetTeam and localTeam == targetTeam then CleanupESP(targetPlayer) -- Clean up ESP for teammates return -- Don't show ESP for teammates end -- If TEAM_CHECK_ENABLED is true but one player has no team, or teams are different, continue... end -- // --- Distance Check --- local localCharacter = LocalPlayer.Character local localHrp = localCharacter and localCharacter:FindFirstChild("HumanoidRootPart") if localHrp then local distance = (hrp.Position - localHrp.Position).Magnitude if distance > MAX_DISTANCE then CleanupESP(targetPlayer) -- Cleanup if too far return -- Stop processing, player is too far end else -- Handle case where local player character hasn't loaded HRP yet CleanupESP(targetPlayer) -- Can't calculate distance, so clean up to be safe return end -- // --- Get or Create ESP Elements --- local espData = espInstances[targetPlayer] if not espData then espData = {} espInstances[targetPlayer] = espData -- // Create BillboardGui (for Name/Health) local billboardGui = Instance.new("BillboardGui") billboardGui.Name = "ESP_Billboard" billboardGui.Adornee = head billboardGui.Size = UDim2.new(0, 200, 0, 70) -- Adjust size as needed billboardGui.StudsOffset = Vector3.new(0, 2.5, 0) -- Offset above the head billboardGui.AlwaysOnTop = true -- The key part for seeing through walls billboardGui.LightInfluence = 0 -- Not affected by world lighting billboardGui.Enabled = (SHOW_NAMES or SHOW_HEALTH) -- Set initial visibility billboardGui.Parent = head -- Parent to head for auto-cleanup (or PlayerGui/CoreGui if preferred) espData.BillboardGui = billboardGui -- // Create Name Label if SHOW_NAMES then local nameLabel = Instance.new("TextLabel") nameLabel.Name = "NameLabel" nameLabel.Size = UDim2.new(1, 0, 0, 20) nameLabel.Position = UDim2.new(0, 0, 0, 0) nameLabel.BackgroundTransparency = 1 nameLabel.TextScaled = true nameLabel.Font = Enum.Font.SourceSansBold nameLabel.TextColor3 = NAME_COLOR nameLabel.Text = targetPlayer.DisplayName -- Use DisplayName or Name nameLabel.Parent = billboardGui espData.NameLabel = nameLabel end -- // Create Health Label if SHOW_HEALTH then local healthLabel = Instance.new("TextLabel") healthLabel.Name = "HealthLabel" healthLabel.Size = UDim2.new(1, 0, 0, 20) healthLabel.Position = UDim2.new(0, 0, 0, 20) -- Position below name healthLabel.BackgroundTransparency = 1 healthLabel.TextScaled = true healthLabel.Font = Enum.Font.SourceSans healthLabel.TextColor3 = Color3.new(0, 1, 0) -- Start Green healthLabel.Parent = billboardGui espData.HealthLabel = healthLabel end -- // Create Health Bar Background (optional) if HEALTH_BAR_ENABLED and SHOW_HEALTH then local healthBarBg = Instance.new("Frame") healthBarBg.Name = "HealthBarBg" healthBarBg.Size = HEALTH_BAR_SIZE healthBarBg.Position = UDim2.new(0.5, -(HEALTH_BAR_SIZE.X.Offset / 2), 0, 40) -- Center below health text healthBarBg.BackgroundColor3 = Color3.fromRGB(50, 50, 50) -- Dark background healthBarBg.BorderSizePixel = 0 healthBarBg.Parent = billboardGui local healthBarFg = Instance.new("Frame") healthBarFg.Name = "HealthBarFg" healthBarFg.Size = UDim2.new(1, 0, 1, 0) -- Full width initially healthBarFg.BackgroundColor3 = Color3.new(0, 1, 0) -- Green foreground healthBarFg.BorderSizePixel = 0 healthBarFg.Parent = healthBarBg espData.HealthBarFg = healthBarFg end -- // Create Highlight (for Outline) if USE_HIGHLIGHT then local highlight = Instance.new("Highlight") highlight.Name = "ESP_Highlight" highlight.Adornee = character highlight.FillColor = HIGHLIGHT_COLOR highlight.OutlineColor = Color3.fromRGB(0,0,0) -- Black outline highlight.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop -- See through walls highlight.FillTransparency = HIGHLIGHT_FILL_TRANSPARENCY highlight.OutlineTransparency = 0.5 highlight.Enabled = true highlight.Parent = character -- Parent to character for auto-cleanup (or CoreGui) espData.Highlight = highlight end end -- // --- Update Dynamic Elements (Health) --- if SHOW_HEALTH and espData.HealthLabel then local health = humanoid.Health local maxHealth = humanoid.MaxHealth local healthPercent = math.clamp(health / maxHealth, 0, 1) espData.HealthLabel.Text = string.format("%.0f / %.0f HP", health, maxHealth) -- Smooth color transition from Red (0%) to Green (100%) espData.HealthLabel.TextColor3 = Color3.fromHSV(healthPercent * (1/3), 1, 1) -- Hue changes from 0 (Red) to 0.33 (Green) -- // Update Health Bar Foreground Size if HEALTH_BAR_ENABLED and espData.HealthBarFg then espData.HealthBarFg.Size = UDim2.new(healthPercent, 0, 1, 0) espData.HealthBarFg.BackgroundColor3 = espData.HealthLabel.TextColor3 end end -- Update Highlight visibility if needed if espData.Highlight and espData.Highlight.Enabled ~= USE_HIGHLIGHT then espData.Highlight.Enabled = USE_HIGHLIGHT end -- Ensure BillboardGui is enabled (if toggled) if espData.BillboardGui and espData.BillboardGui.Enabled ~= (SHOW_NAMES or SHOW_HEALTH) then espData.BillboardGui.Enabled = (SHOW_NAMES or SHOW_HEALTH) end end -- // --- Main Loop --- RunService.RenderStepped:Connect(function() if not LocalPlayer then return end -- Wait for local player local players = Players:GetPlayers() local trackedPlayers = {} -- Keep track of players updated this frame -- // Update ESP for all potentially valid players for i = 1, #players do local player = players[i] if player ~= LocalPlayer then UpdateESP(player) -- If UpdateESP didn't return early (due to team check, death, distance etc.) -- and created/updated ESP, it will exist in espInstances if espInstances[player] then trackedPlayers[player] = true -- Mark as actively tracked this frame end end end -- // Cleanup ESP for players who are no longer valid or left -- // Iterate backwards for safe removal if needed (though assignment to nil is safe) for player, espData in pairs(espInstances) do if not trackedPlayers[player] then -- This player wasn't actively tracked this frame. -- This could be because they left, died, went out of range, OR became a teammate. -- The CleanupESP function is called within UpdateESP for most cases, -- but this catches players who leave instantly between frames. if not table.find(players, player) then -- Check if player actually left the game CleanupESP(player) -- Explicitly clean up if they left end -- Note: Cleanup for becoming a teammate, dying, or going out of range -- is handled *within* the UpdateESP function on the frame it happens. end end end) -- // Optional: Cleanup when the local player leaves Players.PlayerRemoving:Connect(function(player) if player == LocalPlayer then -- Destroy all created ESP elements if the script runner leaves for targetPlayer, _ in pairs(espInstances) do CleanupESP(targetPlayer) end espInstances = {} -- Clear the table -- Optionally disconnect RenderStepped connection here if needed end end) -- // Cleanup when the script itself is destroyed (e.g., PlayerScripts reset) script.Destroying:Connect(function() for targetPlayer, _ in pairs(espInstances) do CleanupESP(targetPlayer) end espInstances = {} print("ESP Script Cleaned Up.") end) print("Team-Based ESP Script Loaded (Educational Use Only - Cheating is Bannable)")