How performant is this? laggy and stutter, or smooth as butter.
depends on how many particles you have. in the video, the rate was 20 and it was pretty buttery smooth.
in a empty place all runs pretty fine, but i think it should run good and better withouth any collisions so.
its anchored, no cancollide, no cantouch, no canquery. all movement is done via script and there are no physics calculations made on the objects. that being said, it is highly recommended that you use this locally in starterplayer because it will look stuttery on the server
i thought about some sort of caching system, i might implement it
Great job!
This is a good resource to have, and I believe this would
be awesome if ROBLOX implemented something similar!
For the time being though, there are a number of things I’d love to see done here to improve performance!
Most of these I’m sure your aware of, so feel free to skip over whatever you feel like.
As mentioned by @CleverTango, Having some form of “Caching System” is a step in the right direction!
But you can build on it by making use of WorldRoot:BulkMoveTo(), to quickly set the CFrames of a large number of particles at once.
This part might be a bit overkill, but using Octrees would be a great idea, since not all active particles are going to be visible from long distances, so slowly moves particles at a certain distance from the camera into the cache. doing so would be a great way to improve performance if done correctly!
If you don’t want to go through through the effort of designing an octree system yourself, @Quenty’s got a great resource you can check out here!
This isn’t anything important, but I appreciate that you included Type-Annotation!
i can see how this would work for the emit function, but i can’t think of a way i would implement it
as for the caching system in general, i think i’ve got something going:
I’m not sure if I used the latest version, but here is a modified copy I made which uses :BulkMoveTo()
In-case you would like to check it out for yourself!
3DP.lua (11.0 KB)
ill implement this, pretty neat!
Hello! Great resource! I was wondering if you could list an example of how to use the module. I tried looking though the code and everything but I couldn’t figure out how to use it.
Other than that though This seems great and I will most likely be using it! Thanks!
(Sorry for the trouble)
you can create it via script and set its properties just as if it were a normal particle emitter. to actually create it, you do ParticleEmitterClass.new(partToEmitFrom, MeshId, TextureId), which returns the emitter for you to set its properties.
I did that but it didn’t seem to do anything when I ran it in-game. I’m sorry for the trouble. Thanks though!
can i see your code? im not sure why its not working
Yeah sure here!
local ParticleSystem = require(game.ReplicatedStorage.ParticleSystem)
ParticleSystem.new(game.Workspace.Part, "rbxassetid://10265263853", "rbxassetid://8444070621")
EDIT: I’m an Idiot. I didn’t know it was disabled by default. My bad!
By any chance can I see the code for the demo in the video? I think that would be cool where like there’s a cave in and you blow it up and rocks fly everywhere.
Sorry for the trouble.
This is super cool! Always wanted to have 3D particles in my games but I couldn’t find a decent way to make that work.
Pretty sure i’m doing something wrong, but I tried to use the module today and I encountered a couple issues:
Particles never being destroyed.wmv (Sorry for the lag, using an old laptop for a few days and on top of that I used the roblox recorder)
As seen in the vid, for some reason the parts are never being removed upon calling :Destroy()? Not only that but they seem to become visible after they are done playing, and they just kind of stay static in the air
here's the code I used
local function WallSlideParticle(Bool)
if Bool == true then
WallSlideEffectPart = Instance.new("Part"); WallSlideEffectPart.CanCollide = false; WallSlideEffectPart.CanTouch = false --I'd love it if this worked with attachments
WallSlideEffectPart.CanQuery = false; WallSlideEffectPart.Size = Vector3.new(1, 1, 1); WallSlideEffectPart.Transparency = 1
WallSlideEffectPart.CFrame = (RootPart.CFrame + Vector3.new(0, 0, -0.5)); WallSlideEffectPart.Parent = RootPart
local Weld = Instance.new("WeldConstraint"); Weld.Parent = WallSlideEffectPart; Weld.Part0 = RootPart; Weld.Part1 = WallSlideEffectPart
WallSlideEffectCall = Particles3D.new(WallSlideEffectPart, WallSlideEffect.Mesh.MeshId, WallSlideEffect.Mesh.TextureId)
WallSlideEffectCall.EmissionDirection = "Top"; WallSlideEffectCall.Lifetime = NumberRange.new(1, 1.2)
WallSlideEffectCall.Rate = 15; WallSlideEffectCall.Speed = 3; WallSlideEffectCall.SpreadAngle = Vector2.new(0, 10)
WallSlideEffectCall.Transparency = NumberSequence.new{
NumberSequenceKeypoint.new(0, 1),
NumberSequenceKeypoint.new(0.3, 0.4),
NumberSequenceKeypoint.new(1, 1),
}
WallSlideEffectCall.Size = NumberSequence.new{
NumberSequenceKeypoint.new(0, 0.2),
NumberSequenceKeypoint.new(0.3, 0.4),
NumberSequenceKeypoint.new(1, 0)
}
WallSlideEffectCall.Enabled = true
else
if WallSlideEffectCall ~= nil then --If the wallslide effect exists
WallSlideEffectCall.Enabled = false --Stop particle
local StoreEffect = WallSlideEffectCall; WallSlideEffectCall = nil --If we touch another wall, we need the variable free again
local StorePart = WallSlideEffectPart; WallSlideEffectPart = nil --If we touch another wall, we need the variable free again
task.delay(1.5, function() --Give the particle time to dissapear
if StoreEffect then --If it still exists destroy it
StoreEffect:Destroy()
end
task.delay(0.5, function() --I assume it takes a bit to destroy the particles so wait a bit before destroying the part
if StorePart then --If its part still exists too, destroy it
StorePart:Destroy()
end
end)
end)
end
end
end
After that I tried removing the cache system, and it kind of did the trick, parts were getting destroyed now (with a couple rare exceptions that I assume didn’t get destroyed due to lag), but particles now showed for a split second before being destroyed.
Transparency and Direction not working.wmv
Then I tried using the exact same code for this walking particle (only difference being the surface and size, but the transparency didn’t seem to change even after removing the wallslide effect and the direction of the particle didn’t seem to follow the part either, as seen in the vid it always goes to the left.
code again
local function SetupRunParticle()
--Get Floor
local CharPos, CharSize = Character:GetBoundingBox()
local Floor = CharPos.Position - Vector3.new(0, CharSize.Y / 2, 0)
--Effect
RunEffectPart = Instance.new("Part"); RunEffectPart.CanCollide = false; RunEffectPart.CanTouch = false
RunEffectPart.CanQuery = false; RunEffectPart.Size = Vector3.new(1, 1, 1); RunEffectPart.Transparency = 1
RunEffectPart.CFrame = (RootPart.CFrame + Vector3.new(0, Floor.Y - RootPart.Position.Y, -0.2)); RunEffectPart.Parent = RootPart
local Weld = Instance.new("WeldConstraint"); Weld.Parent = RunEffectPart; Weld.Part0 = RootPart; Weld.Part1 = RunEffectPart
RunEffectCall = Particles3D.new(RunEffectPart, WallSlideEffect.Mesh.MeshId, WallSlideEffect.Mesh.TextureId)
RunEffectCall.EmissionDirection = "Back"; RunEffectCall.Lifetime = NumberRange.new(0.5, 0.7);
RunEffectCall.Rate = 6; RunEffectCall.Speed = 3; RunEffectCall.SpreadAngle = Vector2.new(10, 0);
RunEffectCall.Transparency = NumberSequence.new{
NumberSequenceKeypoint.new(0, 1),
NumberSequenceKeypoint.new(0.3, 0.4),
NumberSequenceKeypoint.new(1, 1),
}
RunEffectCall.Size = NumberSequence.new{
NumberSequenceKeypoint.new(0, 0.3),
NumberSequenceKeypoint.new(0.3, 0.8),
NumberSequenceKeypoint.new(1, 0)
}
end
local function RunParticle(Bool)
if not RunEffectCall or not RunEffectPart then
SetupRunParticle()
end
if Bool == true and MovesetValue.Value == true then
RunEffectCall.Enabled = true
else
RunEffectCall.Enabled = false
end
end
By this point I was completly lost as to what to do, so I just added the caching system again and to my surprise the walking particles destroyed fine but the wallslide ones still didn’t and the transparency still wasn’t working on the walk particle so I don’t really know what to do about it, hoping i’m doing something wrong on my end.
go ahead and get the latest version from the github, it should fix this stuff!
also, it might be better to just use one particle emitter instead of making new ones
Thanks a lot for the quick response, that fixed it.
As for this transparency bug, it appears to happen when the lifetime of the particle is too short (in my case 0.5-0.7), making it a bit bigger solved that too.
May I get a place file for this?
I like this a lot, I think it should be noted that MeshParts are better to use than SpecialMeshes (see here: Part Instancing - pre-release announcement). Since you can’t change the MeshId live, the script would have to pull from a folder of particle parts too.