Creating a Better Group Only Door (Swinging and Physics)

So we all know about those classic group only doors that kill all players who touch them, should they not be in the relevant group.

This is 2020! As scripters, we have some incredible mechanics at our disposal to create some really well-developed assets that carry out the same purpose. And that’s what we’ll do.

In this thread, we will be utilising the Collisions section of the Physics Service to create a swinging door that is still group-only. Something that I personally haven’t seen a lot of.

Understanding Collisions

To begin with, we need to get our head around how Roblox deals with collisions. Firstly, we’re more professional than the standard “CanCollide” property attached to the BasePart class. Below you can see a video by Roblox demonstrating some of the collisions we’re going to be working with:

Notice how only some of the spheres pass through the block. We will be using this exact logic to create our team only door, substituting spheres for player characters and blocks for our doors.

If you’re unfamiliar with collisions on Roblox (using the PhysicsService), please familiarise yourself with the following article before we continue: Collision Filtering

Our Algorithm

Let’s tackle how we can stop some players going through a door and how to let some through. Well, we can create a single block that stops all players and manually set the collisons to off for players in the right group.

So our algorithm looks something like this:
image

Luckily, Roblox takes care of this for us through the use of the Collisons grouping. So all us developers need to do it tell Roblox which characters to let through, and which to not.

image

Now we have the basic premise of how our script is going to work, we can start dealing with things like data structures and planning exactly how our algorithm is going to work - considering all the cases we can think of: two or more doors per group, player’s in more than one applicable group etc.

Setting out exactly what we need to start up the collisions for the doors:
image

And setting out exactly what we need to start up the collisions for the players:

We are now ready to develop our doors, knowing exactly what we need.

Setting Up Our Door

As always, before we can start scripted we need to make sure our explorer is in order and it has everything we need. I’m going to go ahead and grab the “Door” official model created by Roblox which has our swinging functionality. If you would like to create this door yourself, you can see the following videos created by Roblox:

See videos

1. Making a Door: Vertical Hinge
2. Making a Door: Limits
3. Making a Door: Closing with Springs

So we have our door in studio now.

My explorer

image

Now let’s make our edits. We need to consider lots of cases to make our script truly robust, so let’s say that we’re publishing our model so anyone can use it. We’re going to need some configurations then - the only editable property other developers really need to change will be the GroupId.

My explorer

image

Finally, let’s create that part that will stop all players from walking through the door.

By making this part transparent and anchored, we can ensure that only whitelisted players can travel through this by scripting the collisions as per our algorithm above.

My explorer

image

To incorporate the case of multiple doors, it’s necessary to organise the doors such that they have a common parent in the explorer. To make things neat, I created a folder called “TeamDoors” which also allows us to easily iterate through all the doors in a single for loop.

My explorer


image

Scripting

Finally we can start writing our code. We will firstly tackle setting up our collision groups for our doors; checking whether the group assigned to the door already has a collision group created before another one is made.

-- Roblox Services
local PhysicsService = game:GetService("PhysicsService")

-- Check to see whether a Collision Group already exists
function CollisionGroupExists(ID)
    local CollisionGroups = PhysicsService:GetCollisionGroups()
    for i = 1, #CollisionGroups do
        if CollisionGroups[i].name == "GroupDoor_" .. ID then
            return true
        end
    end
    return false
end

-- Initialise Group Only Door Collisions
for _, Door in pairs (workspace:FindFirstChild("TeamDoors", true):GetChildren()) do
    local Configuration = Door.Configuration
    if not CollisionGroupExists(Door.Configuration.GroupId.Value) then
        PhysicsService:CreateCollisionGroup("GroupDoor_" .. Configuration.GroupId.Value)
    end
end

Next, we need to set up the player characters to have their own collision group:

-- Array to store all groups that have a group-door
local IDs = {}

-- Initialise Player Collisions
game.Players.PlayerAdded:Connect(function(Player)
    for i, ID in pairs (IDs) do
        if Player:IsInGroup(IDs[i]) then
            Player.CharacterAdded:Connect(function(Character)
               for _, Part in pairs (Character:GetDescendants()) do
                   if Part:IsA("BasePart") then
                       PhysicsService:SetPartCollisionGroup(Part, "Players_" .. IDs[i])
                   end
               end
            end)
        end
    end
end)

You’ll notice that we just added a player’s character to an existing Collisions group without first initialising it, this is because we need to make an edit to the original function:

for _, Door in pairs (workspace:FindFirstChild("TeamDoors", true):GetChildren()) do
    local Configuration = Door.Configuration
    if not CollisionGroupExists(Door.Configuration.GroupId.Value) then
        PhysicsService:CreateCollisionGroup("GroupDoor_" .. Configuration.GroupId.Value)
        PhysicsService:CreateCollisionGroup("Players_" .. Configuration.GroupId.Value)
        PhysicsService:CollisionGroupSetCollidable("GroupDoor_" .. Configuration.GroupId.Value, "Player_" .. Configuration.GroupId.Value, false)
    end

    PhysicsService:SetPartCollisionGroup(Door.CollisonsHandler, "GroupDoor_" .. Configuration.GroupId.Value)
end

Conclusion

That’s it! In less than 50 lines of code, we have created a really sleek and modern take on the classic group-only door mechanic. Feel free to add any and all features such as killing the player when they’re not allowed through or teleport pads or anything you can think of!

I hope you enjoyed this tutorial,
-Tom :slight_smile:

Full code
-- Script by ThomasMGardiner

-- Roblox services
local PhysicsService = game:GetService("PhysicsService")

-- System variables
local IDs = {}

-- Check to see whether a Collision Group already exists
function CollisionGroupExists(ID)
	local CollisionsGroups = PhysicsService:GetCollisionGroups()
	for i = 1, #CollisionsGroups do
		if CollisionsGroups[i].name == "GroupDoor_" .. ID then
			return true
		end
	end
	return false
end

-- Initialise Group Only Door Collisions
for i, Door in pairs (workspace:FindFirstChild("TeamDoors", true):GetChildren()) do-- Initialise Door-Player Collisions
	local Configuration = Door.Configuration
	if not CollisionGroupExists(Door.Configuration.GroupId.Value) then
		IDs[i] = Configuration.GroupId.Value
		PhysicsService:CreateCollisionGroup("GroupDoor_" .. Configuration.GroupId.Value)
		PhysicsService:CreateCollisionGroup("Players_" .. Configuration.GroupId.Value)
		PhysicsService:CollisionGroupSetCollidable("GroupDoor_" .. Configuration.GroupId.Value, "Players_" .. Configuration.GroupId.Value, false)
	end
	
	game.PhysicsService:SetPartCollisionGroup(Door.TeamHandler, "GroupDoor_" .. Configuration.GroupId.Value)
end

-- Initialise Player Collisions
game.Players.PlayerAdded:Connect(function(Player)
	for i, ID in pairs (IDs) do
		if Player:IsInGroup(IDs[i]) then
			Player.CharacterAdded:Connect(function(Character)
				print("hi")
				for _, Part in pairs (Character:GetDescendants()) do
					if Part:IsA("BasePart") then
						PhysicsService:SetPartCollisionGroup(Part, "Players_" .. IDs[i])
					end
				end
			end)
		end
	end
end)
14 Likes