We use cookies on this site to enhance your user experience

Top Down Action: Hiding Walls

Top Down Action: Hiding Walls

10 min

If you’ve tested the game in it’s current state, you may have noticed that we can’t see much of the world when we step into the room. Since the camera is at a fixed angle from the character, sometimes walls will get in the way. Let’s add code to make the walls become see-through when a player is inside a room.

Add a new LocalScript|LocalScript to StarterPlayerScripts|StarterPlayerScripts and name it HideWalls. This script will check to see if a player is in a room by seeing what part is underneath the character. If the player is in a room, then it will hide the walls closest to the camera.

Inserting the following code:

local player = game.Players.LocalPlayer

while wait() do
	if player.Character then
		local torso = player.Character:WaitForChild('Torso')
		local ray = Ray.new(torso.Position, Vector3.new(0, -10, 0))
		
		local ignoreList = {}
		
		local part = game.Workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
	end
end

We start off by setting up an infinite loop that only runs its contents if the player’s character exists. If the character does exist, then we make a variable for the player’s torso and create a Ray starting at the character’s torso and pointing 10 studs down. We then create a table (which we will fill later), and use the Workspace/FindPartOnRayWithIgnoreList|FindPartOnRayWithIgnoreList passing in the ray and table we just created. Using the function like this will return a part underneath the character.

Setting up the ignore list

Checking for parts on a ray (typically called a raycast) only yields the first part on the ray that is hit. If the player is standing on a random object in our game, such as a pie, the raycast will hit that object, and we won’t know if the player is standing over the floor of a room or not. To fix this, we will add objects to the ignoreList table. Fortunately, all of the geometry of the building is in the folder LevelGeometry. Anything outside of that folder will be some other part of the game that we don’t really need to check. So, we can simply fill ignoreList with everything in the Workspace|Workspace that isn’t LevelGeometry:

local player = game.Players.LocalPlayer

while wait() do
	if player.Character then
		local torso = player.Character:WaitForChild('Torso')
		local ray = Ray.new(torso.Position, Vector3.new(0, -10, 0))
		
		local ignoreList = {}
		for _, child in pairs(game.Workspace:GetChildren()) do
			if child.Name ~= "LevelGeometry" then
				table.insert(ignoreList, child)
			end
		end
		
		local part = game.Workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
	end
end

Now when we perform the raycast, everything not in LevelGeometry will be ignored.

Keeping track of current room

If you look inside of LevelGeometry you’ll notice that each room in the game has its own Folder|Folder. Inside a room’s Folder is a series of parts called Floor. If the raycast reveals that a player is over a part called Floor, then we just need to check the part’s parent to find out what room we’re in.

local player = game.Players.LocalPlayer
local currentRoom = nil

local function resetCurrentRoom()
	currentRoom = nil
end

while wait() do
	if player.Character then
		local torso = player.Character:WaitForChild('Torso')
		local ray = Ray.new(torso.Position, Vector3.new(0, -10, 0))
		
		local ignoreList = {}
		for _, child in pairs(game.Workspace:GetChildren()) do
			if child.Name ~= "LevelGeometry" then
				table.insert(ignoreList, child)
			end
		end
		
		local part = game.Workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
		if part and part.Name == "Floor" then
			if part.Parent ~= currentRoom then
				resetCurrentRoom()
				currentRoom = part.Parent
			end
		else
			resetCurrentRoom()
		end
	end
end

The currentRoom variable will keep track of which room the player is in. We start it at nil as the player is starting outside and not in any room. We then make a simple function called resetCurrentRoom which simply sets the currentRoom back to nil.

After the raycast, we check if the part that was returned exists and, if so, if it is named Floor. If it is not, then we know that the player is not in a room, and we can simply reset the current room to nil. If the player is over a part called Floor, then we want to see if they are in a different room from the current room. If the player is in a different room then we want to reset the current room and then set the current room to the new one.

Hiding parts

Now let’s add a function to hide parts. Since we only want to hide parts for the player who owns the LocalScript|LocalScript, we can use the BasePart/LocalTransparencyModifier|LocalTransparencyModifier property of BasePart|BasePart.

local player = game.Players.LocalPlayer
local currentRoom = nil

local function setLocalTransparency(object, transparency)
	if object:IsA('BasePart') then
		object.LocalTransparencyModifier = transparency
	end
	for _, child in ipairs(object:GetChildren()) do
		setLocalTransparency(child, transparency)
	end
end

local function resetCurrentRoom()
	currentRoom = nil
end

while wait() do
	if player.Character then
		local torso = player.Character:WaitForChild('Torso')
		local ray = Ray.new(torso.Position, Vector3.new(0, -10, 0))
		
		local ignoreList = {}
		for _, child in pairs(game.Workspace:GetChildren()) do
			if child.Name ~= "LevelGeometry" then
				table.insert(ignoreList, child)
			end
		end
		
		local part = game.Workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
		if part and part.Name == "Floor" then
			if part.Parent ~= currentRoom then
				resetCurrentRoom()
				currentRoom = part.Parent
			end
		else
			resetCurrentRoom()
		end
	end
end

The function setLocalTransparency takes two arguments: the first is the object we want to make transparent and the second is the transparency value we want to set. The function first checks if the object is a BasePart and, if so, sets the local transparency. It then calls setLocalTransparency on all of the children of the object that was passed in. The function is setup like this in case we want to hide Models, Folders, or anything else that may have nested children.

Hiding Rooms

Now that we have a function to hide parts let’s use it to hide the current room. If you look at a Room folder in the game, you’ll notice that it has a Folder called Hide. Hide contains all of the elements of a room that should be hidden if the player is inside of it.

local roomTransparency = 0.5

local player = game.Players.LocalPlayer
local currentRoom = nil

local function setLocalTransparency(object, transparency)
	if object:IsA('BasePart') then
		object.LocalTransparencyModifier = transparency
	end
	for _, child in ipairs(object:GetChildren()) do
		setLocalTransparency(child, transparency)
	end
end

local function setRoomTransparency(room, transparency)
	local hide = room:FindFirstChild("Hide")
	if hide then
		setLocalTransparency(hide, transparency)
	end
end

local function resetCurrentRoom()
	if currentRoom then
		setRoomTransparency(currentRoom, 0)
		currentRoom = nil
	end
end

while wait() do
	if player.Character then
		local torso = player.Character:WaitForChild('Torso')
		local ray = Ray.new(torso.Position, Vector3.new(0, -10, 0))
		
		local ignoreList = {}
		for _, child in pairs(game.Workspace:GetChildren()) do
			if child.Name ~= "LevelGeometry" then
				table.insert(ignoreList, child)
			end
		end
		
		local part = game.Workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
		if part and part.Name == "Floor" then
			if part.Parent ~= currentRoom then
				resetCurrentRoom()
				currentRoom = part.Parent
				setRoomTransparency(currentRoom, roomTransparency)
			end
		else
			resetCurrentRoom()
		end
	end
end

We first setup a variable for the transparency value we want to set see-through objects to. Then we make a new function called setRoomTransparency which takes a room and transparency as arguments. This function first checks to see if the room has a Hide folder. If so, it calls setLocalTransparency on that Folder and passes in its transparency value.

In resetCurrentRoom, we can now use setRoomTransparency to set transparency of the currentRoom to 0 before we change the variable to nil. In our loop when we detect the player is in a new room, we can call setRoomTransparency to make the new room see-through.