So, I decided to make a smoke particle emitter that properly interacts with the world.
What I mean by this is that the smoke will not clip through objects.
It was easy to make, and has probably been done a million times before, but I wanted to just have some fun and make something random.
Here are some clips of it in action:
The code automatically detects when a new smoke object is inserted into workspace, and also starts updating it at the proper rate.
Now, question, should I make this a public asset that anyone can use? I don’t really have a purpose for it.
If I do make this public, do I move the code to be client sided for further optimization?
I have done my best to optimize the code, mainly by changing the update rate depending on how many parts are getting updated. (number of parts / 60)
This number updates every time a new smoke part is detected.
I assume this uses a ray with the lifetime of the particle right? Is there a way to instantly cut off or stop the particles past a certain point without them lingering before disappearing? Pretty cool tho
Yeah, fires a ray upwards with the selected range, and then uses the position difference divided by 2 minus 1 as the particle lifetime.
As for making the particles stop moving up when a part is dropped down onto them, I don’t think that’s possible unless if I start using parts with Billboard GUIs in them as particles instead, which I wont because that’s a terrible idea.
This is the current code, might as well make it public since I just said the math on how the particle lifetime is decided.
if script.Parent ~= game:GetService('ServerScriptService') then local Folder = script.Parent script.Parent = game:GetService('ServerScriptService') Folder:Destroy() end
local UpdateRate = 1/60
local DetectedSmoke = {}
local ActiveSmoke = {}
function SmokeFunctions()
for i, Smoke in pairs(DetectedSmoke) do
if not table.find(ActiveSmoke, Smoke) then
table.insert(ActiveSmoke, Smoke)
task.spawn(function()
while task.wait(UpdateRate) do
local RaycastParamaters = RaycastParams.new()
RaycastParamaters.RespectCanCollide = true
local RayOrigin = Smoke.Position
local RayDirection = Vector3.new(0, Smoke.MaxRange.Value, 0)
local Raycast = workspace:Raycast(RayOrigin, RayDirection, RaycastParamaters)
if not Raycast or not Raycast.Position then Smoke.ParticleEmitter.Lifetime = NumberRange.new(Smoke.MaxRange.Value / 2 - 1) end
if Raycast and Raycast.Position then
local Distance = (RayOrigin - Raycast.Position).Magnitude
Smoke.ParticleEmitter.Lifetime = NumberRange.new(Distance / 2 - 1)
end
end
end)
end
end
end
function CheckForSmoke()
for i, Smoke in pairs(workspace:GetDescendants()) do
if Smoke.Name == 'DynamicSmoke' and Smoke:FindFirstChild("MaxRange") and not table.find(DetectedSmoke, Smoke) then
table.insert(DetectedSmoke, Smoke)
end
end
UpdateRate = #DetectedSmoke/60 or 0
SmokeFunctions()
end
CheckForSmoke()
workspace.DescendantAdded:Connect(CheckForSmoke)