We use cookies on this site to enhance your user experience

Collision Filtering – Team Doors

Collision Filtering – Team Doors

5 min

In many games, it is desirable to have elements of the level that certain players can pass through but others cannot. For instance, in many combat games, players will spawn in a safe area that the other team cannot access (so they aren’t knocked out as soon as they join). There are various ways to accomplish this, but in this tutorial, we will simply be setting up walls that only members of a certain team can pass through.

In our game, we have a level with two teams, a Red team, and a Blue team. Both teams have AutoAssignable set to true so players are added to a team as soon as they join. Each team has a spawn room with a SpawnLocation setup for each team. The entrances to these rooms are covered by translucent parts, each called “ForceField”.

TeamDoorRed.png

TeamDoorBlue.png

To make it so only team members can walk through their respective force fields, we will need to set up several collision groups. One group for each team for the parts of the player’s characters, and one group for each team for their force fields.

local PhysicsService = game:GetService("PhysicsService")

local redForceFields = "RedForceFields"
local blueForceFields = "BlueForceFields"
local redPlayers = "RedPlayers"
local bluePlayers = "BluePlayers"

PhysicsService:CreateCollisionGroup(redForceFields)
PhysicsService:CreateCollisionGroup(blueForceFields)

PhysicsService:CreateCollisionGroup(redPlayers)
PhysicsService:CreateCollisionGroup(bluePlayers)

The force fields parts are in the game at the start, so we can set their collision groups right away.

local PhysicsService = game:GetService("PhysicsService")

local redForceField = game.Workspace.RedStartingZone.ForceField
local blueForceField = game.Workspace.BlueStartingZone.ForceField

local redForceFields = "RedForceFields"
local blueForceFields = "BlueForceFields"
local redPlayers = "RedPlayers"
local bluePlayers = "BluePlayers"

PhysicsService:CreateCollisionGroup(redForceFields)
PhysicsService:CreateCollisionGroup(blueForceFields)

PhysicsService:CreateCollisionGroup(redPlayers)
PhysicsService:CreateCollisionGroup(bluePlayers)

PhysicsService:SetPartCollisionGroup(redForceField, redForceFields)
PhysicsService:SetPartCollisionGroup(blueForceField, blueForceFields)

We can also set up how the groups collide with each other. In this case, the rules are actually pretty simple. In almost every case, we want the groups to collide with each other. Since groups collide with each other by default, we don’t have to set up anything special. All we need to do is define the groups that don’t collide with each other, specifically the teams’ players and the teams’ force fields.

local PhysicsService = game:GetService("PhysicsService")

local redForceField = game.Workspace.RedStartingZone.ForceField
local blueForceField = game.Workspace.BlueStartingZone.ForceField

local redForceFields = "RedForceFields"
local blueForceFields = "BlueForceFields"
local redPlayers = "RedPlayers"
local bluePlayers = "BluePlayers"

PhysicsService:CreateCollisionGroup(redForceFields)
PhysicsService:CreateCollisionGroup(blueForceFields)

PhysicsService:CreateCollisionGroup(redPlayers)
PhysicsService:CreateCollisionGroup(bluePlayers)

PhysicsService:SetPartCollisionGroup(redForceField, redForceFields)
PhysicsService:SetPartCollisionGroup(blueForceField, blueForceFields)

PhysicsService:CollisionGroupSetCollidable(redForceFields, redPlayers, false)
PhysicsService:CollisionGroupSetCollidable(blueForceFields, bluePlayers, false)

Now we need to add the parts of players to the appropriate collision groups. First, we will need to bind events to PlayerAdded and CharacterAdded so we know when we have the character models ready to work with.

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

local redForceField = game.Workspace.RedStartingZone.ForceField
local blueForceField = game.Workspace.BlueStartingZone.ForceField

local redForceFields = "RedForceFields"
local blueForceFields = "BlueForceFields"
local redPlayers = "RedPlayers"
local bluePlayers = "BluePlayers"

PhysicsService:CreateCollisionGroup(redForceFields)
PhysicsService:CreateCollisionGroup(blueForceFields)

PhysicsService:CreateCollisionGroup(redPlayers)
PhysicsService:CreateCollisionGroup(bluePlayers)

PhysicsService:SetPartCollisionGroup(redForceField, redForceFields)
PhysicsService:SetPartCollisionGroup(blueForceField, blueForceFields)

PhysicsService:CollisionGroupSetCollidable(redForceFields, redPlayers, false)
PhysicsService:CollisionGroupSetCollidable(blueForceFields, bluePlayers, false)

local function onCharacterAdded(character, team)
	local collisionGroupName = team.Name .. "Players"
end

local function onPlayerAdded(player)
	player.CharacterAdded:Connect(function(character)
		onCharacterAdded(character, player.Team)
	end)
end

Players.PlayerAdded:Connect(onPlayerAdded)

Note that in onCharacterAdded we need the team of the player so we know what group to add the character’s parts too. To do this, we bind CharacterAdded to an anonymous function which then calls onCharacterAdded (this anonymous function is in the scope of onPlayerAdded so it can access the player variable).

Last we need a function to set the collision group of all of the parts in a character. We will set up a recursive function like we did in the Articles/Player Player Collisions|disable player-player collisions tutorial, but in this case, we will also be passing in the group to add the parts to.

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

local redForceField = game.Workspace.RedStartingZone.ForceField
local blueForceField = game.Workspace.BlueStartingZone.ForceField

local redForceFields = "RedForceFields"
local blueForceFields = "BlueForceFields"
local redPlayers = "RedPlayers"
local bluePlayers = "BluePlayers"

PhysicsService:CreateCollisionGroup(redForceFields)
PhysicsService:CreateCollisionGroup(blueForceFields)

PhysicsService:CreateCollisionGroup(redPlayers)
PhysicsService:CreateCollisionGroup(bluePlayers)

PhysicsService:SetPartCollisionGroup(redForceField, redForceFields)
PhysicsService:SetPartCollisionGroup(blueForceField, blueForceFields)

PhysicsService:CollisionGroupSetCollidable(redForceFields, redPlayers, false)
PhysicsService:CollisionGroupSetCollidable(blueForceFields, bluePlayers, false)

local function setCollisionGroupRecursive(object, groupName)
	if object:IsA("BasePart") then
		PhysicsService:SetPartCollisionGroup(object, groupName)
	end
	for _, child in ipairs(object:GetChildren()) do
		setCollisionGroupRecursive(child, groupName)
	end
end

local function onCharacterAdded(character, team)
	local collisionGroupName = team.Name .. "Players"
	setCollisionGroupRecursive(character, collisionGroupName)
end

local function onPlayerAdded(player)
	player.CharacterAdded:Connect(function(character)
		onCharacterAdded(character, player.Team)
	end)
end

Players.PlayerAdded:Connect(onPlayerAdded)

And that’s all there is to it. Now players can walk through the force fields in front of their spawns, but will be unable to walk into the opposing team’s spawn room.

Tags:
  • team