Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ---------------------------------------------------------------------------------------------------------------------------------------
- -- @CloneTrooper1019, 2018 <3
- -- Particle Library
- -- A client-side library that lets you create and manipulate an individual particle
- ---------------------------------------------------------------------------------------------------------------------------------------
- --[[
- .d8888b. 888 888
- d88P Y88b 888 888
- 888 888 888 888
- 888 .d88b. 88888b. .d8888b 888888 888d888 888 888 .d8888b 888888 .d88b. 888d888 .d8888b
- 888 d88""88b 888 "88b 88K 888 888P" 888 888 d88P" 888 d88""88b 888P" 88K
- 888 888 888 888 888 888 "Y8888b. 888 888 888 888 888 888 888 888 888 "Y8888b.
- Y88b d88P Y88..88P 888 888 X88 Y88b. 888 Y88b 888 Y88b. Y88b. Y88..88P 888 X88
- "Y8888P" "Y88P" 888 888 88888P' "Y888 888 "Y88888 "Y8888P "Y888 "Y88P" 888 88888P'
- ---------------------------------------------------------------------------------------------------
- Particle Particle.new()
- Creates a new Particle.
- ---------------------------------------------------------------------------------------------------
- 8888888b. 888 d8b
- 888 Y88b 888 Y8P
- 888 888 888
- 888 d88P 888d888 .d88b. 88888b. .d88b. 888d888 888888 888 .d88b. .d8888b
- 8888888P" 888P" d88""88b 888 "88b d8P Y8b 888P" 888 888 d8P Y8b 88K
- 888 888 888 888 888 888 88888888 888 888 888 88888888 "Y8888b.
- 888 888 Y88..88P 888 d88P Y8b. 888 Y88b. 888 Y8b. X88
- 888 888 "Y88P" 88888P" "Y8888 888 "Y888 888 "Y8888 88888P'
- 888
- 888
- 888
- ---------------------------------------------------------------------------------------------------
- CFrame Particle.CFrame
- The position and orientation of the particle.
- The orientation is relative to the camera's rotation if FaceCamera is set to true.
- ---------------------------------------------------------------------------------------------------
- Color3 Particle.Color
- The RGB color of the particle.
- ---------------------------------------------------------------------------------------------------
- bool Particle.Enabled
- Toggles whether the particle is drawn and actively updated.
- ---------------------------------------------------------------------------------------------------
- bool Particle.FaceCamera
- Toggles whether the particle should rotate to face the camera.
- ---------------------------------------------------------------------------------------------------
- float Particle.LightEmission
- A number between 0 and 1 indicating how much the particle's color
- blends with the colors behind it.
- ---------------------------------------------------------------------------------------------------
- Vector3 Particle.Orientation
- The 3D orientation of the particle in degrees.
- ---------------------------------------------------------------------------------------------------
- float Particle.Rotation
- The 2D rotation of the particle's texture in degrees.
- ---------------------------------------------------------------------------------------------------
- Vector3 Particle.Scale
- The width, height, and z-offset of the particle in studs.
- This property exists so that :MakeExternalBin() can provide an editor for the Size.
- ---------------------------------------------------------------------------------------------------
- Vector2 Particle.Size
- The width and height of the particle in studs.
- ---------------------------------------------------------------------------------------------------
- Content Particle.Texture
- The URL to the image the particle should use.
- ---------------------------------------------------------------------------------------------------
- float Particle.Transparency
- A number between 0 and 1 indicating the transparency of the particle.
- ---------------------------------------------------------------------------------------------------
- float Particle.ZOffset
- Sets how many studs closer to the camera the Beam is drawn.
- ---------------------------------------------------------------------------------------------------
- 8888888888 888 d8b
- 888 888 Y8P
- 888 888
- 8888888 888 888 88888b. .d8888b 888888 888 .d88b. 88888b. .d8888b
- 888 888 888 888 "88b d88P" 888 888 d88""88b 888 "88b 88K
- 888 888 888 888 888 888 888 888 888 888 888 888 "Y8888b.
- 888 Y88b 888 888 888 Y88b. Y88b. 888 Y88..88P 888 888 X88
- 888 "Y88888 888 888 "Y8888P "Y888 888 "Y88P" 888 888 88888P'
- ---------------------------------------------------------------------------------------------------
- Particle Particle:Clone()
- Returns a copy of the particle.
- ---------------------------------------------------------------------------------------------------
- void Particle:Destroy()
- Deletes the particle and suspends any updates from being performed.
- ---------------------------------------------------------------------------------------------------
- Folder Particle:MakeExternalBin()
- Creates a Folder containing Value objects that correspond to properties of
- the particle. Allows you to view and edit the properties of the particle in
- real time from Roblox Studio.
- ---------------------------------------------------------------------------------------------------
- Signal Particle:GetPropertyChangedSignal(string propertyName)
- Returns a signal that fires when the specified property of the particle is changed.
- ---------------------------------------------------------------------------------------------------
- 8888888888 888
- 888 888
- 888 888
- 8888888 888 888 .d88b. 88888b. 888888 .d8888b
- 888 888 888 d8P Y8b 888 "88b 888 88K
- 888 Y88 88P 88888888 888 888 888 "Y8888b.
- 888 Y8bd8P Y8b. 888 888 Y88b. X88
- 8888888888 Y88P "Y8888 888 888 "Y888 88888P'
- ---------------------------------------------------------------------------------------------------
- Signal Particle.Changed(string propertyName, Variant newValue)
- Fires when one of the Particles properties are changed.
- ---------------------------------------------------------------------------------------------------
- Signal Particle.Destroyed()
- Fires when the particle is destroyed.
- ---------------------------------------------------------------------------------------------------
- --]]
- ---------------------------------------------------------------------------------------------------------------------------------------
- -- Begin Particle Codebase
- ---------------------------------------------------------------------------------------------------------------------------------------
- if game:FindService("NetworkServer") then
- error("Particle library can only be used by LocalScripts.",0)
- end
- local Particle = {}
- local PUBLIC_MEMBERS =
- {
- CFrame = CFrame.new();
- Color = Color3.new(1,1,1);
- Enabled = true;
- FaceCamera = true;
- LightEmission = 1;
- Orientation = Vector3.new();
- Position = Vector3.new();
- Rotation = 0;
- Scale = Vector3.new(1,1,0);
- Size = Vector2.new(1,1);
- Texture = "rbxasset://textures/particles/sparkles_main.dds";
- Transparency = 0;
- ZOffset = 0;
- }
- local push = table.insert
- local pop = table.remove
- local node = Instance.new("Part")
- node.Name = "ParticleNode"
- node.Anchored = true
- node.CanCollide = false
- node.Transparency = 1
- node.Locked = true
- local particleRegistry = {}
- local function getState(particle)
- local state = particleRegistry[particle]
- assert(state, "This particle has been destroyed!")
- return state
- end
- local function assertMember(index)
- assert(PUBLIC_MEMBERS[index], tostring(index) .. " is not a valid member of Particle.")
- end
- local function markDirty(state,member)
- if not state.Private.PendingClean[member] then
- state.Private.PendingClean[member] = true
- push(state.Private.Dirty,member)
- end
- end
- local function setValue(state,member,new)
- markDirty(state,member)
- state.Public[member] = new
- end
- local function tupled(func,...)
- local results = {}
- for i,arg in ipairs{...} do
- results[i] = func(arg)
- end
- return unpack(results)
- end
- ------------------------------------------------------------------------------------------------------------------------------------------
- -- API Declarations
- ------------------------------------------------------------------------------------------------------------------------------------------
- local api =
- {
- Methods = {};
- Bridge = {};
- }
- local newIndexErrorMsg = "Expected %s when setting Particle.%s (got %s)"
- function api.Methods:Clone()
- local newParticle = Particle.new()
- local state = getState(self)
- for member,value in pairs(state.Public) do
- newParticle[member] = value
- end
- return newParticle
- end
- function api.Methods:MakeExternalBin()
- local state = getState(self)
- local modifier = Instance.new("Folder")
- modifier.Name = "Particle"
- for propName,default in pairs(PUBLIC_MEMBERS) do
- local t = typeof(default)
- if t == "boolean" then t = "bool" end
- local className = t:gsub("^.",string.upper) .. "Value"
- local success,value = pcall(Instance.new,className)
- if success and value then
- local updater = self:GetPropertyChangedSignal(propName)
- local function updateValue()
- value.Value = self[propName]
- end
- local function onValueChanged(newValue)
- if self[propName] ~= newValue then
- self[propName] = newValue
- end
- end
- value.Name = propName
- value.Parent = modifier
- updateValue()
- updater:Connect(updateValue)
- value.Changed:connect(onValueChanged)
- end
- end
- local function onDestroyed()
- modifier:Destroy()
- end
- self.Destroyed:Connect(onDestroyed)
- return modifier
- end
- function api.Methods:Destroy()
- local state = particleRegistry[self]
- if state then
- state.Private.Beam:Destroy()
- state.Private.A0:Destroy()
- state.Private.A1:Destroy()
- state.Private.Events.Destroyed:Fire()
- end
- particleRegistry[self] = nil
- end
- function api.Methods:GetPropertyChangedSignal(property)
- local state = getState(self)
- assertMember(property)
- local signal = Instance.new("BindableEvent")
- local function onChanged(name,value)
- if name == property then
- signal:Fire(value)
- end
- end
- self.Changed:Connect(onChanged)
- return signal.Event
- end
- function api.Bridge:__index(member)
- local state = getState(self)
- if api.Methods[member] then
- return api.Methods[member]
- elseif state.Private.Events[member] then
- return state.Private.Events[member].Event
- else
- assertMember(member)
- return state.Public[member]
- end
- end
- function api.Bridge:__newindex(member,new)
- local state = getState(self)
- assertMember(member)
- local expectedType = typeof(PUBLIC_MEMBERS[member])
- local receivedType = typeof(new)
- assert(expectedType == receivedType, newIndexErrorMsg:format(expectedType,member,receivedType))
- setValue(state,member,new)
- end
- ---------------------------------------------------------------------------------------------------------------------------------------
- -- Renderstep Updater
- ---------------------------------------------------------------------------------------------------------------------------------------
- local RunService = game:GetService("RunService")
- local function updateParticles()
- local c = workspace.CurrentCamera
- node.Parent = c
- for particle,state in pairs(particleRegistry) do
- local private = state.Private
- local public = state.Public
- local beam = private.Beam
- local dirty = private.Dirty
- local pending = private.PendingClean
- local updateCF = false
- -- Update any properties that need updating
- while #dirty > 0 do
- local name = pop(dirty)
- local value = public[name]
- if name == "Color" then
- beam.Color = ColorSequence.new(value)
- elseif name == "Transparency" then
- beam.Transparency = NumberSequence.new(value)
- elseif name == "CFrame" then
- updateCF = true
- if public.Position ~= value.p then
- setValue(state,"Position",value.p)
- end
- local ox,oy,oz = tupled(math.deg,value:toOrientation())
- local orientation = Vector3.new(ox,oy,oz)
- if public.Orientation ~= orientation then
- setValue(state,"Orientation",orientation)
- end
- elseif name == "Position" then
- local cf = public.CFrame
- if cf.p ~= value then
- setValue(state,"CFrame",CFrame.new(value)*(cf-cf.p))
- end
- updateCF = true
- elseif name == "Orientation" then
- local cf = public.CFrame
- local pos = cf.p
- local rot = cf-pos
- local ox,oy,oz = tupled(math.rad,value.X,value.Y,value.Z)
- local newRot = CFrame.fromOrientation(ox,oy,oz)
- if rot ~= newRot then
- setValue(state,"CFrame",CFrame.new(pos) * newRot)
- end
- updateCF = true
- elseif name == "Scale" then
- updateCF = true
- beam.Width0 = value.Y
- beam.Width1 = value.Y
- beam.ZOffset = value.Z
- if public.Size.X ~= value.X or public.Size.Y ~= value.Y then
- setValue(state,"Size",Vector2.new(value.X,value.Y))
- end
- if public.ZOffset ~= value.Z then
- setValue(state,"ZOffset",value.Z)
- end
- elseif name == "Size" or name == "ZOffset" then
- local size = public.Size
- setValue(state,"Scale",Vector3.new(size.X,size.Y,public.ZOffset))
- updateCF = true
- elseif name == "Rotation" or name == "FaceCamera" then
- updateCF = true
- elseif name == "Enabled" or name == "LightEmission" or name == "Texture" then
- beam[name] = value
- end
- private.Events.Changed:Fire(name,value)
- pending[name] = nil
- end
- -- Check if we need to update the particle.
- if public.Enabled and public.Transparency < 1 and (updateCF or public.FaceCamera) then
- local cf = public.CFrame
- -- Apply FaceCamera
- if public.FaceCamera then
- local pos = cf.p
- local rot = cf-pos
- cf = CFrame.new(pos,c.CFrame.p) * rot
- end
- -- Apply Rotation
- cf = cf * CFrame.Angles(0,0,math.rad(public.Rotation-90))
- -- Apply Size
- local width = public.Size.X
- private.A0.CFrame = cf * CFrame.new(-width/2,0,0)
- private.A1.CFrame = cf * CFrame.new( width/2,0,0)
- end
- end
- end
- RunService:BindToRenderStep("UpdateParticles",201,updateParticles)
- ---------------------------------------------------------------------------------------------------------------------------------------
- -- Constructor Function
- ---------------------------------------------------------------------------------------------------------------------------------------
- local counter = 0
- function Particle.new()
- local particle = {}
- local state =
- {
- Public = {};
- Private =
- {
- Dirty = {};
- PendingClean = {};
- Events =
- {
- Changed = Instance.new("BindableEvent");
- Destroyed = Instance.new("BindableEvent");
- };
- };
- }
- local name = "Particle" .. tostring(counter)
- counter = counter + 1
- local beam = Instance.new("Beam")
- beam.Name = name .. "_Beam"
- beam.Segments = 1
- beam.TextureSpeed = 0
- beam.Parent = node
- state.Private.Beam = beam
- local a0 = Instance.new("Attachment")
- a0.Name = name .. "_Att0"
- a0.Parent = node
- beam.Attachment0 = a0
- state.Private.A0 = a0
- local a1 = Instance.new("Attachment")
- a1.Name = name .. "_Att1"
- a1.Parent = node
- beam.Attachment1 = a1
- state.Private.A1 = a1
- -- Initialize all members, and subsequently mark them as dirty so the effect will update.
- for member,value in pairs(PUBLIC_MEMBERS) do
- setValue(state,member,value)
- end
- -- Register this particle to be updated
- setmetatable(particle,api.Bridge)
- particleRegistry[particle] = state
- return particle
- end
- return Particle
- ---------------------------------------------------------------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement