Problem with damaging fire

My aim

I’m trying to make a spreading fire that deals damage every second. I used OOP to make a new fire object and created a function :Spread() for it. Now I want every fire part to deal damage every second to the touching players.

Code
local CollectionService = game:GetService("CollectionService")
local Debris = game:GetService("Debris")
local Players = game:GetService("Players")
  
local Fire = {}
Fire.__index = Fire
Fire.Tag = "Fire"
Fire.Cooldown = 1

local IgnoredParts = workspace.IgnoredParts
 
function Fire.new(fire)
	local self = {}
	
	setmetatable(self, Fire)
	
	self.fire = fire
	self.debounce = false
	
	fire.Color = Color3.fromRGB(255,85,0)
	fire.Material = Enum.Material.Neon
	
	return self
end

function Fire:Spread()
	local TouchingParts = self.fire:GetTouchingParts()
	for i,Part in pairs(TouchingParts) do
		if Part.Parent.Name ~= "Meteor" and Part.Parent ~= IgnoredParts then
			if Part:IsA("BasePart") then
				CollectionService:AddTag(Part,"Fire")
			end
		end
	end
end

--------------------------------------------------------------------------

local fires = {}
 
local fireAddedSignal = CollectionService:GetInstanceAddedSignal(Fire.Tag)
local fireRemovedSignal = CollectionService:GetInstanceRemovedSignal(Fire.Tag)
 
local function onFireAdded(fire)
	if fire:IsA("BasePart") then
		fires[fire] = Fire.new(fire)
		Debris:AddItem(fire,math.random(15,20))
		
		wait(math.random(5,10))
		
		fires[fire]:Spread()
	end
end
 
local function onFireRemoved(fire)
	if fires[fire] then
		fires[fire] = nil
	end
end
 
for _,instance in pairs(CollectionService:GetTagged(Fire.Tag)) do
	onFireAdded(instance)
end

fireAddedSignal:Connect(onFireAdded)
fireRemovedSignal:Connect(onFireRemoved)

CollectionService:AddTag(workspace.TestPart,"Fire")

The issue

First off I simply tried to use a .Touched event. The problem is that .Touched doesn not fire if the player is standing still. The next thing I tried is using this piece of code:

function Fire:Activate()
	while wait(1) do
		local TouchingParts = self.fire:GetTouchingParts()
		for i,Part in pairs(TouchingParts) do
			spawn(function()
				local Character = Part.Parent
				if Character then
					local Humanoid = Character:FindFirstChild("Humanoid")
					if Humanoid then
						Humanoid:TakeDamage(10)
					end
				end
			end)
		end
	end
end

Note: I know that this would do damage to a player for every part of his character touching the fire. I removed the debounce to make it easier to read.
For whatever reason the player isn’t touching the part and :GetTouchingParts() returns nil.
grafik

I also tried to insert a player into a table whenever he touches the part (registered with .Touched) and removing him when stopping to touch it (registered with .TouchEnded) and doing damgage to all players in this table. The problem is that both (.Touched and .TouchEnded) are pretty unreliable and don’t register everything.

Looping trough all parts whenever the players magnitude is changed is also no option.

Now I’m running out of options. Is there any other way of doing this?

3 Likes

You can get the part the player is standing on with Raycasting and the Humanoid.FloorMaterial Property.
You use the FloorMaterial Property to find out if the player is in the air, on terrain or a part, and if they stand on a part, you can raycast directly down from the Characters HumanoidRootPart to retrieve the part below it.
Then you can check with the retrieved part if it is burning, and if it is, deal damage.

1 Like

Is this working with damaging walls?

Since there have been no more answers for 3 weeks now Ima bump into this topic again. I still couldn’t find a way to solve this problem

Not sure if this is related to your issue but I think parts with CanCollide set to false won’t work with GetTouchingParts without a TouchInterest object (which gets created when connected to Touch or TouchEnded events.)

In short, try having a part.Touched:Connect(function ()) somewhere before you get touching parts. Also, Touched and TouchEnded fire over and over as the player walks on the part so keep that in mind.

1 Like

I think you should use Region3. If the part is moving i don’t think this is a good idea.

1 Like

All Parts can collide.

Yeah but the problem is that the player won’t get damage if he does not move and that could be exploited.

Try what I suggested, and see if it works (if GetTouchingParts is returning nil. If it’s returning the parts, then just iterate over it every second like

while true do
for _, v in ipairs (part:GetTouchingParts()) do
 -- Check to see if character part, then do damage
end
wait(1)
end

)

1 Like

I already tried this and I’m pretty sure it didn’t work. Anyways Ima try it again.

Just checked, if CanCollide is true, you shouldn’t need to do what I suggested first, you can iterate directly like I’ve shown above.

1 Like

Im already looping through every second in the code above.

while wait(1) do
		local TouchingParts = self.fire:GetTouchingParts()
		for i,Part in pairs(TouchingParts) do
			spawn(function()
				local Character = Part.Parent
				if Character then
					local Humanoid = Character:FindFirstChild("Humanoid")
					if Humanoid and then
						Humanoid:TakeDamage(10)
					end
				end
			end)
		end
	end

Is there anything wrong? I think it’s basically the same as this:

while true do
for _, v in ipairs (part:GetTouchingParts()) do
 -- Check to see if character part, then do damage
end
wait(1)
end

maybe it’s because you have “and” with no condition after, try removing it.
Also, why are you spawning functions when you are not yielding?

1 Like

Oh my fault. I removed some parts of the script to make it easier to understand and forgot to remove that and. Thanks for letting me know

Im spawning funtions because in the original script there’s anoher wait(1)

It’s not working? What’s the issue? Is that your current script now? If it’s not working, try it without spawn. Also, you don’t need to do

local Character = Part.Parent
	if Character then

That’s redundant, that will be true every time.

1 Like

That’s my current function:

function Fire:Activate()
	while wait(1) do
		local Connection = self.fire.Touched:Connect(function() end)
		local TouchingParts = self.fire:GetTouchingParts()
		local DamagedPlayers = {}
		
		Connection:Disconnect()
		for i,Part in pairs(TouchingParts) do
			local Character = Part.Parent
			local Humanoid = Character:FindFirstChild("Humanoid")
			if Humanoid and table.find(DamagedPlayers,Character.Name) then
				table.insert(DamagedPlayers,Character.Name)
				Humanoid:TakeDamage(10)
			end
		end
	end
end

“Connection:Disconnect()” is kind of necessary, instead, have “self.fire.Touched:Connect(function() end)” outside the function (it only needs to run once). And this is if your CanCollide is false. If CanCollide is true GetTouchingParts should work without having to do that.
Also, I think it should be “and not” there. DamagedPlayers should be assigned outside the function. (But yes, the function should clear DamagedPlayers by doing = {} .)

if Humanoid and table.find(DamagedPlayers,Character.Name) then
	table.insert(DamagedPlayers,Character.Name)
	Humanoid:TakeDamage(10)
end

So what happens when the script runs? And try making the changes I showed in this post and see if it works.

EDIT: Sorry if it’s a bit unclear, what I mean is:

local DamagedPlayers = {}
self.fire.Touched:Connect(function() end) -- You can remove this line if CanCollide is true
function Fire:Activate()
	while wait(1) do
		local TouchingParts = self.fire:GetTouchingParts()
		DamagedPlayers = {}
		
		for i,Part in pairs(TouchingParts) do
			local Character = Part.Parent
			local Humanoid = Character:FindFirstChild("Humanoid")
			if Humanoid and not table.find(DamagedPlayers,Character.Name) then
				table.insert(DamagedPlayers,Character.Name)
				Humanoid:TakeDamage(10)
			end
		end
	end
end
1 Like

The problem with simple Touch Events is that they don’t fire if the player is standing still.

Oh right. Thanks for noticing me : The new script now looks like that:

function Fire:Activate()
	local DamagedPlayers = {}
	while wait(1) do
		local Connection = self.fire.Touched:Connect(function() end)
		local TouchingParts = self.fire:GetTouchingParts()
		DamagedPlayers = {}
		
		Connection:Disconnect()
		for i,Part in pairs(TouchingParts) do
			local Character = Part.Parent
			local Humanoid = Character:FindFirstChild("Humanoid")
			if Humanoid and not table.find(DamagedPlayers,Character.Name) then
				table.insert(DamagedPlayers,Character.Name)
				Humanoid:TakeDamage(10)
			end
		end
	end
end

Here’s a file with the neccesary stuff. You can test stuff there:
FireTest.rbxl (18.9 KB)

It doesn’t rely on Touched, it’s just if CanCollide is false you need to do that to create a TouchInterest object. Do you mean that GetTouchingParts is not working?

Also test file doesn’t work:
MinigameIslands is not a valid member of Workspace
Script ‘ServerScriptService.Fire’, Line 10

1 Like

Oh I’m sorry Ima fix this :sweat_smile: