GetPartsObscuringTarget()

I have a custom camera and I’m trying to replicate the default invisicam which doesn’t work with my custom camera.

This code works, but I was wondering on how I could make the parts which are no longer obscuring the camera visible?

game:GetService("RunService").RenderStepped:connect(function()
	
	local parts = Camera:GetPartsObscuringTarget({rootPart.CFrame.p},Character:GetChildren())
	
	for index, value in ipairs(parts) do
		value.Transparency = 1
	end

end)

Save which parts you make invisible into a table, and compare the table with your GetPartsObscuringTarget call to see which are invisible but not obscuring target.

1 Like

What’s the most efficient way to see if something is in one table but not the other? I just tried to do it but didn’t work out too well and the code looks super inefficient

game:GetService("RunService").RenderStepped:connect(function()
	
	local parts = Camera:GetPartsObscuringTarget({rootPart.CFrame.p},Character:GetChildren())
	
	for index, value in ipairs(parts) do
		local inTable = false
		for i = 1,#invisibleParts do
			if invisibleParts[i] ~= value then
				inTable = false
			else
				inTable = true
			end
		end
		if inTable == false then
			table.insert(invisibleParts, value)
			value.Transparency = 1
		end
	end
	
	for i = 1,#invisibleParts do
		local inTable = true
		for index, value in ipairs(parts) do
			if invisibleParts[i] ~= value then
				inTable = false
			else
				inTable = true
			end
		end
		if inTable == false then
			invisibleParts[i].Transparency = 0
			table.remove(invisibleParts,i)
		end
	end

end)
1 Like

You should set LocalTransparencyModifier instead of setting the Transparency property directly so that you don’t have to remember the original Transparency of each part every frame. Here’s some code that should work:

local obscuringParts = {}
local Camera = workspace.CurrentCamera

game:GetService("RunService").RenderStepped:connect(function()
    -- Reset the LocalTransparencyModifier of parts from the previous frame.
	for _, part in pairs(obscuringParts) do
		part.LocalTransparencyModifier = 0
	end	
	
	-- Assuming that you defined rootPart and Character elsewhere...	
	obscuringParts = Camera:GetPartsObscuringTarget({rootPart.CFrame.p},Character:GetChildren())
	
    -- Make parts that obscure the character transparent.
	for _, part in pairs(obscuringParts) do
		part.LocalTransparencyModifier = 1
	end	
end)
6 Likes
Dictionaries

With arrays, you have numerical indexes and any values. This makes it a list, like

array = {
	[1] = "First item!",
	[2] = "Second item!",
	[3] = "Third item!",
	[4] = "Fourth item!",
}

You can access these items with array[1] or array[3]

You can loop over this array using for index, value in pairs(array) do


With dictionaries, you have keys instead of indexes, and they can be anything! A common example is strings:

dictionary = {
	["Name"] = "Corecii",
	["Color"] = Color3.new(0, 0, 1),
	["Goggles"] = true,
}

You can access these items with array["Name"] or array["Goggles"]

You can loop over this dictionary using for key, value in pairs(dictionary) do


Dictionaries can also have parts as their keys. This means if you save all of your last transparent parts in a dictionary dictionary[part] = true, you can then use dictionary[some_part] == true to check if some_part was made transparent last time.

Similarly, if you make a dictionary of all of the new parts, you can do new_dictionary[some_part] == true to check if some_part is obscuring the camera in the new obscuring parts list.

You can use dictionary[part] ~= true to check if a part is not in one of the dictionaries.

Here is a simple example
local lastDictionary = {}

game:GetService("RunService").RenderStepped:connect(function()
	
	local parts = Camera:GetPartsObscuringTarget({rootPart.CFrame.p},Character:GetChildren())

	local newDictionary = {}

	for index, part in ipairs(parts) do
		part.Transparency = 1
		newDictionary[part] = true
	end

	for part, value in pairs(lastDictionary) do  -- `value` will always be `true`; we don't really need it
		if newDictionary[part] ~= true then  -- check if `part` was *not* in the new parts list
			part.Transparency = 0  -- if not in the list, we need to make it visible again
		end
	end

	lastDictionary = newDictionary  -- on the next renderstep, it will use our newDictionary to check what parts to make visible
end)

This is not the most optimal example, but it’s good for learning dictionaries.

Here is an optimal example
local partDictionary = {}

game:GetService("RunService").RenderStepped:connect(function()
	
	local parts = Camera:GetPartsObscuringTarget({rootPart.CFrame.p},Character:GetChildren())

	for index, part in ipairs(parts) do
		part.Transparency = 1
		partDictionary[part] = false
	end

	for part, value in pairs(partDictionary) do  -- value will be false if it's in the new parts list, and true if it was in the last one
		if value then  -- [1]
			part.Transparency = 0
			partDictionary[part] = nil  -- [2]
		else
			partDictionary[part] = true 
		end
	end
	-- we have just removed all previously `true` (last) keys, and set all `false` (new) keys to `true`
	-- all of the values in `partDictionary` are `true` now. on the next run, those will be the last-run keys.
	-- if it encounters any of the same parts, then `partDictionary[part]` will be set to `false` first, and
	--  the only `true` parts left over will be the old ones. then the cycle repeats.

	-- this uses only one dictionary and doesn't create a new one every frame
	-- creating new tables is not a huge issue, but it's better to avoid it if you know how.
end)


-- [1]:
--  if-then statements check the "truthiness" of values. for example:
--  `if a == true then` is the same as `if a then` when `a` is a true/false value
--  `a == true` actually gives you `true` or `false`, and the `if` checks against that
--  you can even use values like `"Hello World!"`, `5`, or `Workspace`
--  here's the rule:
--   if the value is `false` or `nil`, it's considered `false`
--   if the value is anything else, it's considered `true`
-- [2]:
--  this removes the part from the dictionary
--  it's fine to reassign or remove values from a dictionary in a pairs loop
--  see http://lua-users.org/wiki/TablesTutorial

Dictionaries aren’t actually necessary for this, and @XAXA’s example works fine. I figured that this would still be an informative “tutorial” that might teach you something new, so I decided to post it anyway.

3 Likes