How to make a ghost player/npc

I made a ghost system a few months back, and it recently started breaking, i cant find any type of fix to this so i decided to would completly replace it with a new one, how are people able to achive this? is my question, as ive seen games doing this, like Blotch and Poltergeist Perception, if anyone can teach me or give me advice on how to recreate this system id greatly appreciate it

1 Like

Can you elaborate on what “ghost system” entails and what exactly you’re looking for here? Not everyone that will read your thread will have played the games you listed, so you need to detail the system you’re working with rather than give existing examples.

Additionally, are you not able to just start fixing that broken system instead of creating a whole new one? If you’ve already created one in the past, you should know the fundamental concept at least of what you’re looking to achieve. You can then do some research based off of that to see what items you’re going to need. For example: need a player somewhat transparent? Check out BasePart.Transparency.

When posting help requests to this category, please make sure to include detail to your posts. Explanations of your systems, code samples and media would help better identify what you’re trying to do and the problem so you can be better helped.

You also don’t need to feel obligated to reply to every single post if you believe it’s not helpful, because then it creates noise for threads like this and it’s difficult to make out signal for other developers who are actually trying to be helpful or have the same problem and are looking for help.

Finally, please do not mark posts as solutions if they don’t actually answer your question. You also cannot close threads as they are public resources, discussion remains open so long as the replies stay contributive towards the topic at hand.

Im trying to achieve a system where only a certain group of players can see another group of players or npcs, ive made a system before and it just recently broke, as i just said, i used bool values to determine if the player/npc is a ghost or not, and if its a ghost it will set all its body parts to transparency 1, so the other player doesnt see them, i used client sided scripting before, but i dont know why it started breaking recently

Could you detail the issues about your current system? What is breaking about it? Do you know exactly where at the very least the error is occurring, perhaps something is showing up in your console? Can you show us code samples and media about what’s happening and what should be happening? These details are crucial and need to be supplied for us to better help you.

normal players are able to see the ghost players/npcs without the value that is required to see them, i would show the code but im pretty embarrased about it, not to mention its outdated and pretty bad, i could send it on private messages or anything else

That’s what the forum is for. Even if your code is embarrassing, no one is (or should be) laughing at you for it. We come here to learn and to better our craft and in doing so, help others along the way. You need to be able to supply this information when posting a help request. Without these details, there’s not much we can do besides putting you to your own devices to do research and testing for a new system.

1 Like
LocalScript
 while true do
    	wait()
    	for _,v in pairs (game.Workspace:GetDescendants()) do			
    		if v.Name == "Humanoid" and v.Parent:IsA("Model") then
   
    	
    			local effect = v.Parent:FindFirstChild("Effects")
    			local plreffect = script.Parent.Parent:WaitForChild("Effects")
    			
    			if effect.Ghost.Value == true then			

    				v.Parent["Right Arm"].Transparency = 0
    				v.Parent["Right Leg"].Transparency = 0
    				v.Parent["Left Arm"].Transparency = 0
    				v.Parent["Left Leg"].Transparency = 0
    				v.Parent["Torso"].Transparency = 0
    				v.Parent["Head"].Transparency = 0
    				
    			end		
    		end			
    	end	
    end

this is part of a local script, the script that enables and disables the local script itself activates when the “CanSeeGhosts” value is changed to true/false

Thanks for sharing. Yeah, I think that you might want to update your code to newer standards to make it better on performance, especially in adopting an event-driven system over loops. Additionally, it’d be super expensive and heavy to iterate over the descendants of the workspace in a non-terminating while loop at minimum waiting time.

My favourite service for handling groups of objects that I need to modify is CollectionService. With this, it makes it easy (and fun) to quickly apply effects in large amounts. For example, a LocalScript can define the behaviour of ghosting a character while all your code needs to do is add a tag to the relevant objects in order to apply or unapply the effects.

So you can easily modify transparency, I recommend changing to use LocalTransparencyModifier instead of using Transparency directly. LocalTransparencyModifier is a hidden client-only property that allows you to control rendering transparency while preserving the real transparency as this is a multiplier. When you go into first person mode, your character fading off is a result of this being set on your character’s parts by the camera scripts.

First thing you may want to do is to tag all your NPCs with some kind of tag, like “NPC”, so that you can easily recognise them. In the explorer window, select all the NPCs possible to appear in your game and write the following in the command bar:

for _, selected in ipairs(game:GetService("Selection"):Get()) do
    game:GetService("CollectionService"):AddTag(selected, "NPC")
end

You’ll also need a way to tag characters since they can also be ghosts too, if I’ve read your post correctly. Set up a server script or edit an existing one that just tags characters as they’re added.

local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")

local function playerAdded(player)
    player.CharacterAdded:Connect(function (character)
        CollectionService:AddTag(character, "Character")
    end)

    if player.Character then
        CollectionService:AddTag(character, "Character")
    end
end)

Players.PlayerAdded:Connect(playerAdded)

Now for your LocalScript, this can control the ghosting effect for characters and NPCs. We’ll use a “Ghost” tag to identify who should become invisible when the tag is added. We’ll be using the events CollectionService kindly provides us to our advantage to apply these effects. New LocalScript, preferably should be in StarterPlayerScripts:

local CollectionService = game:GetService("CollectionService")

local GHOST_TAG = "Ghost"

local function objectAdded(object)
    if not CollectionService:HasTag(object, "Character") or not CollectionService:HasTag(object, "NPC") then return end

    for _, part in ipairs(object:GetDescendants()) do
        if part:IsA("BasePart") or part:IsA("Decal") then
            part.LocalTransparencyModifier = 1
        end
    end
end

local function objectRemoved(object)
    if not CollectionService:HasTag(object, "Character") or not CollectionService:HasTag(object, "NPC") then return end

    for _, part in ipairs(object:GetDescendants()) do
        if part:IsA("BasePart") or part:IsA("Decal") then
            part.LocalTransparencyModifier = 0
        end
    end
end

CollectionService:GetInstanceAddedSignal(GHOST_TAG):Connect(objectAdded)
CollectionService:GetInstanceRemovedSignal(GHOST_TAG):Connect(objectRemoved)
for _, object in ipairs(CollectionService:GetTagged(GHOST_TAG)) do
    objectAdded(object)
end

With this, that’s basically a new system done that’s much more performant. A tidbit to keep in mind is that I did not code this under the assumption that your scripts would ever add new parts to characters (e.g. like hats, tools, so on): if they do, you’ll need to do a bit more work where you track DescendantAdded connections to new objects in the objectAdded function and disconnect them in objectRemoved. This code only writes transparency once and then never again.

Now, in place of any code you might have that sets the Ghost value of the Effects folder in a character or NPC, you will instead use CollectionService to add the “Ghost” tag to the character model. As an example: pretend you have an NPC in the workspace named Foobar. Foobar is a character model.

local CollectionService = game:GetService("CollectionService")
CollectionService:AddTag(workspace.Foobar, "Ghost") -- Now spooky! Ooh.
wait(3)
CollectionService:RemoveTag(workspace.Foobar, "Ghost") -- Unspooky.

Hopefully this bit makes sense. To repeat: instead of setting the value of a Ghost ValueObject in your Effects folder, you use CollectionService to tag a character or NPC model with “Ghost” to make this work. That being said, I didn’t actually test this myself, so I have no idea if it even works - I just have confidence in the code I write on the fly, so worth giving it a quick test.

If you don’t understand anything, feel free to do a bit of your own debugging, research on the Developer Hub or forward me some questions and I’ll see if I can answer them.

2 Likes

thanks for the help, even though i didnt ask for someone to make an entire system for me, i greatly appreciate it, and will be sure to try and use it tomorrow, goodnight!