Make all players in map locally invisible

What I am trying to achieve is making all the players not visible to one player in the map. Is this possible? I am trying to achieve this from a local script. If anyone knows how to do this, it would help a lot if they can provide an answer.

9 Likes

From my understanding you can simply iterate through all the players in the game and if it isn’t that client’s player, then you can simply set all their limbs transparency to 1.

Although you might still bump into them as I don’t think there’s an easy way to make them non-cancollidable, except maybe CollisionGroups.

5 Likes
-- whenever you want to make the players invisible,

local Players = game:GetService("Players")
local localPlayer = Players.LocalPlayer

-- looping through players, making sure it's not the local player
for _, player in ipairs(Players:GetPlayers()) do

	if player ~= localPlayer then

		-- find the character, wait if the character doesn't exist
		local char = player.Character or player.CharacterAppearanceLoaded:Wait()

		-- loop through ALL parts under the character
		for _, part in ipairs(char:GetDescendants()) do

			-- make sure the part is a base part so that properties exist
			if part:IsA("BasePart") then

				-- change properties

				part.Transparency = 1

				-- part.CanCollide = false

			end
		end
	end
end

You could probably just make them CanCollide false on the client, since it wouldn’t replicate because of FE and the physics would be owned by the respective player.

6 Likes

Interesting, although I was referring more so that when you attempt to change a limb’s CanCollide state to false, it always switches back to true because of it being a Humanoid.

Could be wrong here though.

3 Likes

I tried your code;

local Players = game:GetService("Players")
local localPlayer = Players.LocalPlayer
for _, player in ipairs(Players:GetPlayers()) do

	if player ~= localPlayer then
		local char = player.Character or player.CharacterAdded:Wait()
		for _, part in ipairs(char:GetDescendants()) do
			if part:IsA("BasePart") then
					part.Transparency = 1
				           char:WaitForChild("Head").OverHead.Enabled = false
			end
		end
	end
end

Issue is, for some players this didn’t make them invisible. I had friends help me test.

3 Likes

They are using R15, because I have the characters pre-set to R15.

2 Likes

The End Effect

I assume you want something like this:
https://gyazo.com/8b974cf3836cc91cbe78a6db05b47042
The players could stay invisble if you wanted, this is just to demonstrate the full functionality.

Setting every other player’s character’s part’s transparency

To make a player invisible, we have to set every part in their character’s transparency to 1, making it invisible. We can do this by iterating through players, then their character’s parts. Using a recursive function makes this even easier to do.

The local script for the player:

local hide = true --Whether to hide, can be manipulated

local orignalTransparency = {}--Store original transparency

local function checkPart(part) --This will set the transparency of every part
	for a,b in pairs(part:GetChildren()) do 
		checkPart(b) --If there are more parts, also set the transparency for them too
	end
	if part:IsA("BasePart") or part:IsA("Decal") then--If the object is a part or decal, set it's transparency. (Face is a decal)
		if hide then --If we want to hide players, make their parts invisible
			if not orignalTransparency[part] then--Store data for later if we want to undo the effect
				orignalTransparency[part] = part.Transparency
			end
			part.Transparency = 1
		else --If we don't want to hide, set the transparency back to normal
			if orignalTransparency[part] then --If we stored it
				part.Transparency = orignalTransparency[part] --Set it
				orignalTransparency[part] = nil --Remove reference because we do not need it anymore, prevents memory leaks
			end
		end
	end
end

local players = game:GetService("Players")
local localPlayer = players.LocalPlayer

game:GetService("RunService").RenderStepped:Connect(function() --Every frame, set transparency
	--Iterate through players to make them invisible
	for i,v in pairs(players:GetPlayers()) do --Go through every player
		if v ~= localPlayer then --This makes sure we don't make ourself invisble. Remove this for everyone.
			local char = v.Character
			if char then--If the character exists
				checkPart(char)
			end
		end
	end
	--Prevent memory leaks, if a part does not exist anymore we do not need to reference it
	for part,trans in pairs(orignalTransparency) do
		if not part then
			orignalTransparency[part] = nil
		elseif not part.Parent then
			orignalTransparency[part] = nil
		end
	end
end)

while true do --Testing functionality
	hide = true
	wait(2.5)
	hide = false
	wait(2.5)
end

DEMO Download:

If you want a working DEMO, here it is:
InvisOtherPlayersDEMO.rbxl (15.8 KB)

Several Problems and Notes

Exploiters would still be able to bypass this method. To make it exploit proof, the characters would have to be custom and replicated selectively by the server. Since everything is done locally, it could be reversed.

Another problem you might have is that players collide with each other, even if they are invisible. You could fix this by having a one collision group for the seaker and another for the regular players, and make them not collide. Or, just make players not collide in general.

Note Mar 31st, 2024

Note that this loop is just an example - you should not have a while true loop with a wait, or tying this directly to RenderStepped. You should be connecting to an event that occurs when the state changes and using that. For example, you could have a hidden Bool attribute for each player that you connect to with AttributeChanged.

38 Likes

You also might want to make other players invisible whenever they join the game, using Players.PlayerAdded, and when they respawn using Player.CharacterAdded. But this depends on the scenario

1 Like
Old Post

You would need to put this code in some kind of loop, such as a

while true do
    --Run code
    wait()
end

or bind it to renderStepped. This code would only execute once upon joining.

Edit March 31st, 2024: Do not do this. Use connections.

1 Like

It seems pointless to be looping through the players continuously instead of just changing them all when you want them to be changed. This doesn’t seem efficient. Would be better to just change the character’s transparency based on a remote event or a value changing in replicated storage, for example.

4 Likes

Changing transparency every frame for every 100 humanoid characters seems to cause no significant delay. I don’t think that updating transparency to the same value changes anything.

It seems that once the value is set, it doesn’t cause any update by setting it again.
For example:

part.Transparency = 1
wait(1)
part.Transparency = 1--Doesn't do anything

Edit March 31st, 2024: this is not true. While updating a property that is already set to the same value does not do anything, the actual act of iterating over thousands of parts every frame is expensive.

1 Like

Just because it doesn’t cause a delay doesn’t mean it isn’t bad practice - I could do a lot of things every frame but this doesn’t mean I couldn’t be doing them in a more efficient way :shrug:

4 Likes
Removed

This text will be hidden
My point is, both ways work. Your way is better practice. You do have a point with using connections, it’s just you would have to disconnect them too. Instead of changing values every frame, you could check to see if a character has already been modified. That way, you do not loop through them every frame.

Modified Code:

local hide = true --Whether to hide, can be manipulated

local orignalTransparency = {}--Store original transparency

local function checkPart(part) --This will set the transparency of every part
	for a,b in pairs(part:GetChildren()) do 
		checkPart(b) --If there are more parts, also set the transparency for them too
	end
	if part:IsA("BasePart") or part:IsA("Decal") then--If the object is a part or decal, set it's transparency. (Face is a decal)
		if hide then --If we want to hide players, make their parts invisible
			if not orignalTransparency[part] then--Store data for later if we want to undo the effect
				orignalTransparency[part] = part.Transparency
			end
			part.Transparency = 1
		else --If we don't want to hide, set the transparency back to normal
			if orignalTransparency[part] then --If we stored it
				part.Transparency = orignalTransparency[part] --Set it
				orignalTransparency[part] = nil --Remove reference because we do not need it anymore, prevents memory leaks
			end
		end
	end
end

local players = game:GetService("Players")
local localPlayer = players.LocalPlayer
local modified = {}

game:GetService("RunService").RenderStepped:Connect(function() --Every frame, set transparency
	--Iterate through players to make them invisible
	for i,v in pairs(players:GetPlayers()) do --Go through every player
		if v ~= localPlayer then --This makes sure we don't make ourself invisble. Remove this for everyone.
			local char = v.Character
			if char and (not modified[char] or not hide) then--If the character exists and is not already modified
                                modified[char]  = true
				checkPart(char)
			end
		end
	end
	--Prevent memory leaks, if a part does not exist anymore we do not need to reference it
	for part,trans in pairs(orignalTransparency) do
		if not part then
			orignalTransparency[part] = nil
		elseif not part.Parent then
			orignalTransparency[part] = nil
		end
	end
	for char,bool in pairs(modified) do
		if not char then
			modified[char] = nil
		elseif not modified.Parent then
			modified[char] = nil
		end
	end
        
end)

while true do --Testing functionality
	hide = true
	wait(2.5)
	hide = false
	wait(2.5)
end

Thank you for your correction, you do have a point. The above code uses better practice as it checks to make sure it has not already updated a character first. Have a good day.

Edit March 31st, 2024: this post is wrong, use connections.

5 Likes

I know this is an old post, but we had a game that used your exact code and we had a major lag problem that increased fast when more players joined.

The lag started as soon as 10 to 15 players.

Let me put this into perspective:

let’s assume we have 100 humanoid avatars that are R15.

That’s 100 x 15 parts to check per character, so 1500 parts per frame, you are running this function:

local function checkPart(part) --This will set the transparency of every part
	for a,b in pairs(part:GetChildren()) do 
		checkPart(b) --If there are more parts, also set the transparency for them too
	end
	if part:IsA("BasePart") or part:IsA("Decal") then--If the object is a part or decal, set it's transparency. (Face is a decal)
		if hide then --If we want to hide players, make their parts invisible
			if not orignalTransparency[part] then--Store data for later if we want to undo the effect
				orignalTransparency[part] = part.Transparency
			end
			part.Transparency = 1
		else --If we don't want to hide, set the transparency back to normal
			if orignalTransparency[part] then --If we stored it
				part.Transparency = orignalTransparency[part] --Set it
				orignalTransparency[part] = nil --Remove reference because we do not need it anymore, prevents memory leaks
			end
		end
	end
end

You are running this somewhat expensive around 75000 times per second.

Now i am aware you have code that prevents this, but you still have expensive code that runs for every frame:

--Prevent memory leaks, if a part does not exist anymore we do not need to reference it
	for part,trans in pairs(orignalTransparency) do
		if not part then
			orignalTransparency[part] = nil
		elseif not part.Parent then
			orignalTransparency[part] = nil
		end
	end
	for char,bool in pairs(modified) do
		if not char then
			modified[char] = nil
		elseif not modified.Parent then
			modified[char] = nil
		end
	end

this alone is causing major lag issues.

This should only run ONCE when needed. I.e, only when the server starts, or when you click a button or when a player’s character loads, etc.


I just wanted to add on to this post as a heads up, because there can be some people may still be finding and using this code, such as my friend did, and I really wanted to emphasize how quickly problems like these can escalate.

Never run expensive code with large loops every frame. It’s a recipe for a lag machine.

I mean this in the nicest way btw, i don’t want this sounding offense. Just letting you and others aware.

Yep - if you can tie this to an event you should. The good thing is that’s easy to do with the function.

Using a RenderStepped hook for this was definitely wrong. Especially when higher numbers of characters are becoming more and more common, doing things the right way is important.

The time consuming part of this loop is the looping over every part - which means this issue will also scale by a huge amount as you add players.

I’ll make a fix to this - in the meantime I’ve edited the incorrect posts and added a note to the main one.

1 Like