Changing a Player's collision group via touching a certain Terrain

  1. What do you want to achieve? When touching terrain (Example: Grass) Changes Collision group of player who touch terrain to Noclipped

  2. What is the issue? When touching terrain grass it won’t change the player’s collision group to Noclipped.

  3. What solutions have you tried so far? I looked at the documentation of Collision groups and the Dev forums related too the topic with no avail.

I want to touch a terrain (I used grass for example) and when I touch it will make me who touch it change my player’s collision group to Noclipped. I want to do a shimmer effect like in Terraria.

(Local Script)

local rs = game:GetService("RunService")
local player = game:GetService("Players").LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoid = char:WaitForChild("Humanoid")

-- Get the RemoteEvent from ReplicatedStorage
local replicatedStorage = game:GetService("ReplicatedStorage")
local floorMaterialChangedEvent = replicatedStorage.Events.FloorMaterialChanged

humanoid:GetPropertyChangedSignal("FloorMaterial"):Connect(function()
	rs.Stepped:Wait()

	-- Check if the player is standing on grass
	if (humanoid.FloorMaterial) == Enum.Material.Grass then
		-- Fire the RemoteEvent
		print("Event Fired")
		floorMaterialChangedEvent:FireServer(true)
	else
		-- Fire the RemoteEvent
		floorMaterialChangedEvent:FireServer(false)
	end
end)

(ServerScript)

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


PhysicsService:RegisterCollisionGroup("Players")
PhysicsService:RegisterCollisionGroup("Noclipped")

-- Get the RemoteEvent from ReplicatedStorage
local floorMaterialChangedEvent = replicatedStorage.Events.FloorMaterialChanged
print("EventGot")
local function onFloorMaterialChanged(characterModel, isOnGrass)
	local player = Players:GetPlayerFromCharacter(characterModel)
	if player then
		-- Check if the player is standing on grass
		if isOnGrass then
			-- Change the collision group to Noclip for each BasePart
			for _, part in pairs(characterModel:GetDescendants()) do
				if part:IsA("BasePart") then
					part.CollisionGroup = "Noclipped"
				end
			end
		else
			-- Revert the collision group to Characters for each BasePart
			for _, part in pairs(characterModel:GetDescendants()) do
				if part:IsA("BasePart") then
					part.CollisionGroup = "Players"
				end
			end
		end
	end
end

-- Connect the function to the RemoteEvent
floorMaterialChangedEvent.OnServerEvent:Connect(onFloorMaterialChanged)
4 Likes

So I believe I figured it out to a single local script, but is there a better way to track if a player is touching terrain without FloorMaterial or raycast?

local rs = game:GetService("RunService")
local player = game:GetService("Players").LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoid = char:WaitForChild("Humanoid")

humanoid:GetPropertyChangedSignal("FloorMaterial"):Connect(function()
	rs.Stepped:Wait()

	-- Check if the player is standing on grass
	if (humanoid.FloorMaterial) == Enum.Material.Grass then
		-- Change the CanCollide of all parts to false
		for _, child in pairs(char:GetChildren()) do
			if child:IsA('BasePart') then
				child.CollisionGroup = "Noclipped"
			end
		end
	end
end)
1 Like

Looks good, you don’t need this though:

You might also want to loop over every descendant, so it will also catch accessory parts.

And keep in mind, if you’re changing the .CollisionGroup on the client, it won’t replicate to the server.

2 Likes

Uh CollisionGroups changed on the client get effect to the server. You cannot delete or create new collisiongroups on the client tho. I might be wrong but I tested this in studio.

1 Like

Oh, I guess it replicates to the server when you change your own character’s collision groups then. I’m fairly sure changing anchored parts and other object’s collision groups doesn’t replicate though.

Probably yeah changing CanCollide and Anchor won’t replicate. Just happy it works in a minimal amount of code without dealing with RemoteEvents and such. Do you know any other way I can keep track of what terrain the player is on?

The only sensible ways are FloorMaterial and Raycasts, so your code is good.

1 Like

Alright, thanks dude :+1: . I do hope they implent other methods of keeping track of Roblox Terrain stuff.

Finished Script For Anyone To Use. (Local Script)

local player = game:GetService("Players").LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoid = char:WaitForChild("Humanoid")

humanoid:GetPropertyChangedSignal("FloorMaterial"):Connect(function()

	-- Check if the player is standing on grass
	if (humanoid.FloorMaterial) == Enum.Material.Grass then
		for _, child in pairs(char:GetChildren()) do
			if child:IsA('BasePart') then
				child.CollisionGroup = "Noclipped" -- Change Noclipped to name of collision group
			end
		end
	end
end)
2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.