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.
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