Using Raycast to change material

Hi! I want to make a script that makes my model’s rock’s material change to the material of the part that they touched when spawning. (default material is set to slate)
The script runs perfectly fine, but the model’s rocks doesnt change material.

video that shows the problem:
https://gyazo.com/f13eacb9c477a918565430c25ec42f50
script:

local rs = game:GetService("ReplicatedStorage")
local RemoteEvent = rs:WaitForChild("RockFolder"):WaitForChild("RemoteEvent")

RemoteEvent.OnServerEvent:Connect(function(player)
	local character = player.Character
	local humanoid = character:WaitForChild("Humanoid")
	local humrp = character:WaitForChild("HumanoidRootPart")
	
	local rocksFolder = Instance.new("Folder", workspace)
	rocksFolder.Name = player.Name.."'s rocks"
	
	local rocks = rs:WaitForChild("RockFolder"):WaitForChild("rocks"):Clone()
	rocks.Parent = rocksFolder
	rocks:PivotTo(CFrame.new(humrp.Position) * CFrame.new(0,-15,0))
	
	local tweenService = game:GetService("TweenService")
	local goal = {
		Position = rocks:WaitForChild("Part").Position + Vector3.new(0,15,0)
	}

	local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
	local tweenPos = tweenService:Create(rocks:WaitForChild("Part"), tweenInfo, goal)
	
	tweenPos:Play()
	-- changing the model's rocks material
	local rayParams = RaycastParams.new()
	rayParams.FilterDescendantsInstances = {workspace.Ignore}
	rayParams.FilterType = Enum.RaycastFilterType.Blacklist

	for i, v in pairs(rocks:GetChildren()) do
		local ray = workspace:Raycast(v.CFrame.Position, v.CFrame.UpVector, rayParams)
		if ray then
			v.Material = ray.Instance.Material
		end
	end
	
	for i, v in pairs(rocks:GetChildren()) do
		if v.Name == "Rock" then
			local goal2 = {
				Transparency = 0
			}
			local tweenT = tweenService:Create(v, tweenInfo, goal2)
			tweenT:Play()
		end
	end
	wait(2)
	for i, v in pairs(rocks:GetChildren()) do
		for i, Attachment in pairs(v:GetChildren()) do
			for i, Attachment in pairs(Attachment:GetChildren()) do
				if Attachment.Name == "particle" then
					Attachment.Enabled = true
				end
			end
		end
	end
	
	wait(5)
	
	rocksFolder:Destroy()
	
	RemoteEvent:FireClient(player)
end)

Thanks in advance

2 Likes

I think the problem is that you need to raycast downwards, and that your raycast should be longer than one.

You probably want to sample directly downwards, so for the direction use something like Vector3.down or Vector3.new(0, -1, 0) (both are the same) multiplied by how long you want the raycast to be. I’d recommend something like 10-100 studs.

These changes result in this:

local ray = workspace:Raycast(v.CFrame.Position, Vector3.down*100, rayParams)
1 Like

Vector3.down*100 is underlined in the script and i got this error

'ServerScriptService.RocksServerFolder.RocksServer:31: attempt to perform arithmetic (mul) on nil and number '
1 Like

Whoops! That’s my bad, I had this mixed up with the unity api. Roblox hasn’t added a down value yet.

local ray = workspace:Raycast(v.CFrame.Position, Vector3.yAxis*-100, rayParams)

Try that code.

2 Likes

Oof the code runs perfectly fine, but the rocks didn’t change material

2 Likes

Here is some code that can (probably) debug the problem:

local rs = game:GetService("ReplicatedStorage")
local RemoteEvent = rs:WaitForChild("RockFolder"):WaitForChild("RemoteEvent")

RemoteEvent.OnServerEvent:Connect(function(player)
	local character = player.Character
	local humanoid = character:WaitForChild("Humanoid")
	local humrp = character:WaitForChild("HumanoidRootPart")
	
	local rocksFolder = Instance.new("Folder", workspace)
	rocksFolder.Name = player.Name.."'s rocks"
	
	local rocks = rs:WaitForChild("RockFolder"):WaitForChild("rocks"):Clone()
	rocks.Parent = rocksFolder
	rocks:PivotTo(CFrame.new(humrp.Position) * CFrame.new(0,-15,0))
	
	local tweenService = game:GetService("TweenService")
	local goal = {
		Position = rocks:WaitForChild("Part").Position + Vector3.new(0,15,0)
	}

	local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
	local tweenPos = tweenService:Create(rocks:WaitForChild("Part"), tweenInfo, goal)
	
	tweenPos:Play()
	-- changing the model's rocks material
	local rayParams = RaycastParams.new()
	rayParams.FilterDescendantsInstances = {workspace.Ignore}
	rayParams.FilterType = Enum.RaycastFilterType.Blacklist

	for i, v in pairs(rocks:GetChildren()) do
		local ray = workspace:Raycast(v.CFrame.Position, Vector3.new(0, -100, 0), rayParams)
		if ray then
			if (ray.Instance == v) then print("Ray hit the rock instead of the ground! Parent the rocksFolder to Workspace.Ignore.")
			else if (ray.Instance:IsDescendantOf(rocksFolder)) then print("Ray hit another rock! Parent the rocksFolder to Workspace.Ignore.") end end
			print("The raycast had a valid hit! Material was: "..ray.Instance.Material.Name)
			v.Material = ray.Instance.Material
		else
			print("The raycast didn't hit anything! Check direction and ignore list!")
		end
	end
	
	for i, v in pairs(rocks:GetChildren()) do
		if v.Name == "Rock" then
			local goal2 = {
				Transparency = 0
			}
			local tweenT = tweenService:Create(v, tweenInfo, goal2)
			tweenT:Play()
		end
	end
	wait(2)
	for i, v in pairs(rocks:GetChildren()) do
		for i, Attachment in pairs(v:GetChildren()) do
			for i, Attachment in pairs(Attachment:GetChildren()) do
				if Attachment.Name == "particle" then
					Attachment.Enabled = true
				end
			end
		end
	end
	
	wait(5)
	
	rocksFolder:Destroy()
	
	RemoteEvent:FireClient(player)
end)
2 Likes

ok so i parented the rocksFolder to the Ignore folder
as told in the part of the script below:

if (ray.Instance == v) then print("Ray hit the rock instead of the ground! Parent the rocksFolder to Workspace.Ignore.")

But then i got another error which i dont really understand:

'ServerScriptService.RocksServerFolder.RocksServer:35: attempt to concatenate string with EnumItem'

And also, it printed out that

'The raycast didnt hit anything! Check direction and ignore list!'

The first message means it hit something. The second means it didn’t hit something.

That’s weird, it should set the material of the rock if it’s giving that error message. Are you sure the material of the rocks can be set? It’s not a mesh with a texture?

Edit:
I fixed the debug code (I needed EnumItem.Name) in the original reply.

I dont know if the material of the rocks can be set, but its not a mesh with a texture, just a mesh

1 Like

Oh, Actually it printed out a lot, but it still didn’t change the material of the rocks though
image

Oh, it looks like the raycasts are hitting the rocks instead of the ground. To fix this, set the rocksFolder parent to Workspace.Ignore instead of just workspace.

local rocksFolder = Instance.new("Folder", workspace:WaitForChild("Ignore"))
1 Like

uh know it prints out this:

"The raycast didn't hit anything! Check direction and ignore list! (x46)  -  Server - RocksServer:42"

i checked ignore list, and it looks fine [?]
image.
How do i check direction though

So before it was hitting a rock, now it isn’t hitting anything.

I assume the ground isn’t in the Ignore folder.

I think the problem is that the rocks are inside the ground, so when it raycasts it checks below the ground instead checking below where the rocks will be.

This code starts the raycast from where the tween ends, and raycasts 100 studs downwards:

local ray = workspace:Raycast(v.CFrame.Position + Vector3.new(0, 15, 0), Vector3.new(0, -100, 0), rayParams)

Edit:

Only put the rocks folder in ignore :+1:

Glad I could help!

1 Like

wait, the ground has to be in the ignore folder? (these)
also, the line script u sent above solved the problem thanks a lot!!