Hey there! I recently made a module to help with easily emitting particles.
I was thinking of making this a community resource but I’m wondering if there’s any way I can improve my code before then:
(Put this in a module script, then put all your particle emitters you want to use with this under the module script and name them)
--[[
Particle Query by @baseparts on 9/3/22
-----------------------
local ParticleQuery = require(Modules.ParticleQuery)
local Particles = ParticleQuery.new(number_here) -- The # is the starting amount of emitters
Particles:Start() -- Begins updating / heartbeat
Particles:Emit(
Type : string, -- Name of the emitter. All emitters are stored under this module script before the game starts
CFrame : CFrame, -- CFrame of where the particles will be emitted
Size : any, -- Size of the emitter part. Allows to have a bunch of particles emitted within a space. This is not the be confused with the "Size" property under ParticleEmitters
Amount : number -- Number of particles emitted
)
Particles:Resize(number_here) -- Resizes the number of emitters
Particles:Pause() -- Stops updating / heartbeat
-----------------------
Extra Notes:
The lower the number of emitters means the less number of particles being updated / heartbeat
Lower number of emitters should also mean less lag (Untested)
-----------------------
]]
local Terrain = workspace.Terrain
local RunService = game:GetService("RunService")
local Particles = {}
Particles.__index = Particles
local Vector3Zero = Vector3.zero
local function GetNewPart(Parent)
local Part = Instance.new("Part")
Part.Size = Vector3Zero
Part.Position = Vector3Zero
Part.Anchored = true
Part.CanCollide = false; Part.CanQuery = false; Part.CanTouch = false
Part.Transparency = 1
Part.Parent = Parent
return Part
end
local function GiveAllParticleEmitters(Part)
for _, Emitter in pairs(script:GetChildren()) do
Emitter.Enabled = false
Emitter.LockedToPart = false
Emitter:Clone().Parent = Part
end
end
local function ResizeNumberOfEmitters(self, NewAmount)
local CurrentAmount = #self.__emitters
if NewAmount < CurrentAmount then
for i = 1, CurrentAmount - NewAmount do
self.__emitters[1]:Destroy()
end
elseif NewAmount > CurrentAmount then
for i = 1, NewAmount - CurrentAmount do
local Emitter = GetNewPart(self.__core)
GiveAllParticleEmitters(Emitter)
table.insert(self.__emitters, Emitter)
end
end
end
local function UpdateQuery(self)
for i = 1, #self.__emitters do
if self.__query[i] then
self.__emitters[i].CFrame = self.__query[i].CFrame
self.__emitters[i].Size = self.__query[i].Size or Vector3Zero
self.__emitters[i][self.__query[i].Type]:Emit(self.__query[i].Amount)
table.remove(self.__query, i)
end
end
end
local function new(Emitters : number)
local self = {}
self.__emitters = {}
self.__query = {}
self.__core = GetNewPart(Terrain)
self.__connection = nil
self.Running = false
self.__core.Name = "EmitterCore"
ResizeNumberOfEmitters(self, Emitters)
return setmetatable(self, Particles)
end
local function Start(self)
if self.Running == false and self.__connection == nil then
self.Running = true
self.__connection = RunService.Heartbeat:Connect(function()
UpdateQuery(self)
end)
end
end
local function Pause(self)
if self.Running == true and self.__connection ~= nil then
self.Running = false
self.__connection:Disconnect()
self.__connection = nil
end
end
local function Emit(self, Type : string, CFrame : CFrame, Size : any, Amount : number)
table.insert(self.__query, {
Size = Size or nil,
Type = Type,
CFrame = CFrame,
Amount = Amount
})
end
Particles.new = new
Particles.Start = Start
Particles.Pause = Pause
Particles.Emit = Emit
Particles.Resize = ResizeNumberOfEmitters
return Particles