[PLEASE HELP] Forcefield material is incredibly performant heavy [PLEASE HELP]

I have a touched event that fires when a character part touches it. The event makes all parts within that character forcefield material. it lags a ton. Any way to fix this?

incineratorZone.Touched:Connect(function(hit)
	-- Use BasePart check to cover all part-like objects
	if hit:IsA("BasePart") and not touchedparts[hit] then
		print(hit)
		-- Immediately mark as processed to prevent race conditions
		touchedparts[hit] = true

		task.spawn(function()
			-- Visual effects
			hit.Material = Enum.Material.ForceField
			hit.Color = Color3.fromRGB(252, 0, 255)

			-- Non-blocking delay
			task.wait(0.3)

			-- Cleanup
			hit:Destroy()
			touchedparts[hit] = nil
		end)
	end
end)
1 Like

this script only affects the body part that touched incineratorZone, it doesn’t change the whole character

Well… in my case it does because it touches all the player body parts. The reason i do this is because i want it to be gradual–as each part touches the incinerator zone i want it to become forcefield material. In any case, I am asking for help to make it less laggy. not what the script does.

I guess since all the parts of the character call the function it’s gonna lag
actually there might be a lot less lag if you got rid of the print statement

It would be helpful if you elaborated on what you mean by lag, do the frames drop? Does the ping spike? What exactly is happening? Why do you think it’s the material’s fault?

Frames drop a ton. I have found a temporary solution by adding a wait(0.1) so that the materials change on seperate frames. Are forcefield materials always so unperformant?

Three different attempts combined at smoothing this out.

local incineratorZone = script.Parent
local touchedCharacters = {}

incineratorZone.Touched:Connect(function(hit)
	if not hit:IsA("BasePart") then return end
	
	local character = hit.Parent
	if character and not touchedCharacters[character] then
		touchedCharacters[character] = true

		task.spawn(function()
			for _, part in ipairs(character:GetChildren()) do
				if part:IsA("BasePart") then
					part.Material = Enum.Material.ForceField
					part.Color = Color3.fromRGB(252, 0, 255)
				end
			end
			
			task.wait(0.3)
			if character then
				character:Destroy()
			end

			touchedCharacters[character] = nil
		end)
	end
end)
1 Like

This is great! However, as I said I want it to be gradual–when each part touches it, it turns into the forcefield material. I would also like it to only apply to the touching parts and not the whole char.

I knew you would come back with that … :rofl: I’m looking for a solid base to work from. I’m sure you can implement what you want to that. The biggest thing here is a controlled de-bounce. Can not have that firing at will … Swapping the material should not be a problem at all … Over calling that will.

Why have you put a task.spawn? There isn’t any code after it so it’s sort of just wasteful

Checking if character here is pointless because the variable is never assigned-to after it has already been checked by the first if. character will always refer to the Character model, even if it is :Destroy’d, because the variable is holding a reference to it that prevents it from actually being deleted. Values cannot spontaneously become false or nil unless the code explicitly sets them as such, thus the check will never fail as that is all that is needed for the condition to pass.

This is a common way to stop a script fail error. When you’re waiting there is always a chance the player could just exit the game. Script errors on the next line and never recovers.

As far as the task.spawn there is a whole function after that. As I said this is a multiple attempt at stopping the problem. Take from it what works for you…

If you have something to help with this question why don’t you post your attempt.
Why even comment on my post … :rofl:

1 Like

I to blame roblox materials for my script lagging :slight_smile:

You can try this but if it isn’t up to your standards idk what is.

local touchedParts = {}
incineratorZone.Touched:Connect(function(Hit: BasePart) 
	if not Hit:IsA("BasePart") then return end --// if "Hit" isn't a BasePart (Part, UnionOp, Mesh) then return
	if touchedParts[Hit] then return end --// if "Hit" is already in "touchedParts" then return, code for Hit object has already been ran.
	if not Hit.Parent or not Hit.Parent:FindFirstChildOfClass("Humanoid") then return end --// if "Hit" doesn't have a parent (it should but it had a type checking issue so..)
	-- or if Hit isn't a direct child of Character then return
	
	touchedParts[Hit] = true
	
	Hit.Material = Enum.Material.ForceField
	Hit.Color = Color3.fromRGB(252, 0, 255)
	
	task.delay(0.3, function() --// Waits 0.3 seconds then runs code in function
		if not Hit.Parent then --// Checking to see if the parent is nil cause if the Hit is destroyed we still have the reference to the direct object but the Hit (should) be parented to nil.
			touchedParts[Hit] = nil
			return
		end
		
		Hit:Destroy()
		touchedParts[Hit] = nil
	end)
end)

Touched events are fired continuously, and print too many print statements will also lag out studio badly, especially with certain output window formatting options. You should logic in your touched handler so that it doesn’t run any code on redundant touched events, and remove the print() call or move it to where it at least doesn’t fire for every Touched event.

Forcefield material is probably a red herring, there’s nothing particularly expensive about it, it’s just a shader trick.

You can debounce per part and do batch processing so instead of processing every touch event instantly, use a queue system.

local incineratorZone = script.Parent
local touchedparts = {} 
local processingQueue = {}

local function processPart(hit)
	if hit:IsA("BasePart") and not touchedparts[hit] then
		touchedparts[hit] = true

		task.spawn(function()
			for i = 1, 5 do
				if hit and hit.Parent then
					hit.Material = Enum.Material.ForceField
					hit.Color = Color3.new(1, 0, 1) 
					hit.Transparency = hit.Transparency + 0.2
				end
				task.wait(0.1) 
			end

			if hit and hit.Parent then
				hit.Transparency = 1
				hit.CanCollide = false
				hit.CanTouch = false
				task.wait(1)
				hit:Destroy()
			end

			touchedparts[hit] = nil 
		end)
	end
end

incineratorZone.Touched:Connect(function(hit)
	if hit:IsA("BasePart") and hit.Parent and hit.Parent:FindFirstChild("Humanoid") then
		table.insert(processingQueue, hit)
	end
end)

task.spawn(function()
	while true do
		if #processingQueue > 0 then
			local hit = table.remove(processingQueue, 1)
			if hit then
				processPart(hit)
			end
		end
		task.wait(0.1)
	end
end)

So no lag spikes and your Gradual effect still remains etc…

An error cannot occur here because character can never become nil within the scope, even if the Player leaves the game ¯\_(ツ)_/¯

It’s just a nitpick on code quality. I am just informing you that you can save time and remove a few lines of code that do nothing, it is for your and other people’s benefit to know that the check is not necessary.

Ya I just guess on these and spit it out. I need something to test with to be sure. Just a few possible fixes… He will have to test this stuff for himself.

“character can never become nil within the scope” You’re correct here.

1 Like

The print might actually be causing most of the lag since when the character walks into the zone, it might have to print out a lot of parts all at once from the character.

When I remove that, my machine does not lag. If it truly is the material, then there’s nothing to be done other than not use it.

Edit: So apparently, I missed reading some previous messages because there were several other people who mentioned the print being the issue before I did. If I would have realized that I wouldn’t have posted this, mb. If it is the print, give the solution to the first person who pointed it out. keeping this up to reemphasize the print is probably the issue.

2 Likes

Yeah the print is what’s going to do the most performance when testing in studio, if this post did anything it just proved theirs always more than 1 solution to a problem.

2 Likes

If it will error (it won’t in this case), it will stop execution of that thread only, and in case of connected function, it will stop only that fired connection once, and won’t impact further executions.