I made this fire-spreading script for a project I’m working on with some others. The script picks a valid BasePart
in the current map to be the source of the fire, then spreads the fire from there.
The script also deals with the lifetime of the fire, such as making it turn into ashes after a certain amount of time. The fire works similarly to the fire in Natural Disaster Survival.
Script Performance
Script
-- This code has since been rewritten
local CollectionService = game:GetService("CollectionService")
local PlayerService = game:GetService("Players")
local random = Random.new()
local currentMap = workspace.CurrentMap
local mapDescendants = currentMap:GetDescendants()
local fireColors = {"Bright yellow", "Bright orange"}
local ashColors = {"Black"}
local sourcePartCount = 1
local spreadCooldownRange = {0.025, 0.10}
local spreadQueue = {}
local function getSourceParts()
local sourceParts = {}
for index = 1, sourcePartCount do
local sourcePart
local noFire
local isBasePart
repeat task.wait()
sourcePart = mapDescendants[random:NextInteger(1, #mapDescendants)]
noFire = CollectionService:HasTag(sourcePart, "NoFire")
isBasePart = sourcePart:IsA("BasePart")
until isBasePart and not noFire
table.insert(sourceParts, sourcePart)
end
return sourceParts
end
local function getNearbyParts(part)
local nearbyParts = {}
local fireParts = CollectionService:GetTagged("Fire")
local ashParts = CollectionService:GetTagged("Ash")
local noFire = CollectionService:GetTagged("NoFire")
local size = part.Size
local offset = Vector3.new(size.X + 0.55, size.Y + 0.55, size.Z + 0.55)
local parameters = OverlapParams.new()
parameters.FilterDescendantsInstances = {part, fireParts, ashParts, noFire}
parameters.FilterType = Enum.RaycastFilterType.Exclude
nearbyParts = workspace:GetPartBoundsInBox(part.CFrame, offset, parameters)
return nearbyParts
end
local function addToLifetime(part)
while task.wait(1) do
local lifetime = part:GetAttribute("Lifetime") or 0
part:SetAttribute("Lifetime", lifetime + 1)
end
end
local function changePart(part, partType)
if partType == "Fire" then
table.insert(spreadQueue, part)
local randomColor = random:NextInteger(1, #fireColors)
local randomWait = random:NextInteger(20, 30)
part.Material = Enum.Material.Neon
part.BrickColor = BrickColor.new(fireColors[randomColor])
CollectionService:AddTag(part, "Fire")
coroutine.wrap(addToLifetime)(part)
end
if partType == "Ash" then
local randomColor = random:NextInteger(1, #ashColors)
part.Material = Enum.Material.Slate
part.BrickColor = BrickColor.new(ashColors[randomColor])
CollectionService:RemoveTag(part, "Fire")
CollectionService:AddTag(part, "Ash")
end
end
local function updateParts()
local fireParts = CollectionService:GetTagged("Fire")
local ashParts = CollectionService:GetTagged("Ash")
for index, part in fireParts do
local lifetime = part:GetAttribute("Lifetime") or 0
if lifetime > random:NextInteger(10, 15) then
if not part.Anchored then
part:BreakJoints()
end
end
if lifetime > random:NextInteger(40, 50) then
changePart(part, "Ash")
end
end
for index, part in ashParts do
local lifetime = part:GetAttribute("Lifetime")
if lifetime > random:NextInteger(70, 80) then
local weld = part:FindFirstChild("Weld")
if weld then
return
end
if part.Anchored then
return
end
part:Destroy()
end
end
end
local function spread(source)
local nearbyParts = getNearbyParts(source)
for index, part in nearbyParts do
local isDescendant = part:IsDescendantOf(currentMap)
if not isDescendant then
continue
end
changePart(part, "Fire")
end
end
local sourceParts = getSourceParts()
for index, part in sourceParts do
spread(part)
end
for index, part in spreadQueue do
local rangeNumberOne = spreadCooldownRange[1]
local rangeNumberTwo = spreadCooldownRange[2]
local randomCooldown = random:NextNumber(rangeNumberOne, rangeNumberTwo)
spread(part)
updateParts()
task.spawn(function()
while true do
local randomCooldown = random:NextNumber(2, 5)
spread(part)
updateParts()
task.wait(randomCooldown)
end
end)
task.wait(randomCooldown)
end