Advertisement
CloneTrooper1019

[Roblox] Particle Library

Jan 21st, 2018
654
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.26 KB | None | 0 0
  1. ---------------------------------------------------------------------------------------------------------------------------------------
  2. -- @CloneTrooper1019, 2018 <3
  3. -- Particle Library
  4. -- A client-side library that lets you create and manipulate an individual particle
  5. ---------------------------------------------------------------------------------------------------------------------------------------
  6.                                                                                                                                    --[[
  7.      .d8888b.                             888                              888                              
  8.     d88P  Y88b                            888                              888                              
  9.     888    888                            888                              888                              
  10.     888         .d88b.  88888b.  .d8888b  888888 888d888 888  888  .d8888b 888888  .d88b.  888d888 .d8888b  
  11.     888        d88""88b 888 "88b 88K      888    888P"   888  888 d88P"    888    d88""88b 888P"   88K      
  12.     888    888 888  888 888  888 "Y8888b. 888    888     888  888 888      888    888  888 888     "Y8888b.
  13.     Y88b  d88P Y88..88P 888  888      X88 Y88b.  888     Y88b 888 Y88b.    Y88b.  Y88..88P 888          X88
  14.      "Y8888P"   "Y88P"  888  888  88888P'  "Y888 888      "Y88888  "Y8888P  "Y888  "Y88P"  888      88888P'
  15.                                                                                                                    
  16.     ---------------------------------------------------------------------------------------------------
  17.         Particle    Particle.new()
  18.                     Creates a new Particle.
  19.     ---------------------------------------------------------------------------------------------------
  20.            
  21.     8888888b.                                             888    d8b                  
  22.     888   Y88b                                            888    Y8P                  
  23.     888    888                                            888                          
  24.     888   d88P 888d888  .d88b.  88888b.   .d88b.  888d888 888888 888  .d88b.  .d8888b  
  25.     8888888P"  888P"   d88""88b 888 "88b d8P  Y8b 888P"   888    888 d8P  Y8b 88K      
  26.     888        888     888  888 888  888 88888888 888     888    888 88888888 "Y8888b.
  27.     888        888     Y88..88P 888 d88P Y8b.     888     Y88b.  888 Y8b.          X88
  28.     888        888      "Y88P"  88888P"   "Y8888  888      "Y888 888  "Y8888   88888P'
  29.                                 888                                                    
  30.                                 888                                                    
  31.                                 888                                                    
  32.  
  33.     ---------------------------------------------------------------------------------------------------
  34.         CFrame      Particle.CFrame
  35.                     The position and orientation of the particle.
  36.                     The orientation is relative to the camera's rotation if FaceCamera is set to true.
  37.     ---------------------------------------------------------------------------------------------------
  38.         Color3      Particle.Color
  39.                     The RGB color of the particle.
  40.     ---------------------------------------------------------------------------------------------------
  41.         bool        Particle.Enabled
  42.                     Toggles whether the particle is drawn and actively updated.
  43.     ---------------------------------------------------------------------------------------------------
  44.         bool        Particle.FaceCamera
  45.                     Toggles whether the particle should rotate to face the camera.
  46.     ---------------------------------------------------------------------------------------------------
  47.         float       Particle.LightEmission
  48.                     A number between 0 and 1 indicating how much the particle's color
  49.                     blends with the colors behind it.
  50.     ---------------------------------------------------------------------------------------------------
  51.         Vector3     Particle.Orientation
  52.                     The 3D orientation of the particle in degrees.
  53.     ---------------------------------------------------------------------------------------------------
  54.         float       Particle.Rotation
  55.                     The 2D rotation of the particle's texture in degrees.
  56.     ---------------------------------------------------------------------------------------------------
  57.         Vector3     Particle.Scale
  58.                     The width, height, and z-offset of the particle in studs.
  59.                     This property exists so that :MakeExternalBin() can provide an editor for the Size.
  60.     ---------------------------------------------------------------------------------------------------
  61.         Vector2     Particle.Size
  62.                     The width and height of the particle in studs.
  63.     ---------------------------------------------------------------------------------------------------
  64.         Content     Particle.Texture
  65.                     The URL to the image the particle should use.
  66.     ---------------------------------------------------------------------------------------------------
  67.         float       Particle.Transparency
  68.                     A number between 0 and 1 indicating the transparency of the particle.
  69.     ---------------------------------------------------------------------------------------------------
  70.         float       Particle.ZOffset
  71.                     Sets how many studs closer to the camera the Beam is drawn.
  72.     ---------------------------------------------------------------------------------------------------
  73.  
  74.     8888888888                         888    d8b                            
  75.     888                                888    Y8P                            
  76.     888                                888                                  
  77.     8888888 888  888 88888b.   .d8888b 888888 888  .d88b.  88888b.  .d8888b  
  78.     888     888  888 888 "88b d88P"    888    888 d88""88b 888 "88b 88K      
  79.     888     888  888 888  888 888      888    888 888  888 888  888 "Y8888b.
  80.     888     Y88b 888 888  888 Y88b.    Y88b.  888 Y88..88P 888  888      X88
  81.     888      "Y88888 888  888  "Y8888P  "Y888 888  "Y88P"  888  888  88888P'
  82.  
  83.     ---------------------------------------------------------------------------------------------------
  84.         Particle    Particle:Clone()
  85.                     Returns a copy of the particle.
  86.     ---------------------------------------------------------------------------------------------------
  87.         void        Particle:Destroy()
  88.                     Deletes the particle and suspends any updates from being performed.
  89.     ---------------------------------------------------------------------------------------------------
  90.         Folder      Particle:MakeExternalBin()
  91.                     Creates a Folder containing Value objects that correspond to properties of
  92.                     the particle. Allows you to view and edit the properties of the particle in
  93.                     real time from Roblox Studio.
  94.     ---------------------------------------------------------------------------------------------------
  95.         Signal      Particle:GetPropertyChangedSignal(string propertyName)
  96.                     Returns a signal that fires when the specified property of the particle is changed.
  97.     ---------------------------------------------------------------------------------------------------
  98.  
  99.     8888888888                            888            
  100.     888                                   888            
  101.     888                                   888            
  102.     8888888    888  888  .d88b.  88888b.  888888 .d8888b  
  103.     888        888  888 d8P  Y8b 888 "88b 888    88K      
  104.     888        Y88  88P 88888888 888  888 888    "Y8888b.
  105.     888         Y8bd8P  Y8b.     888  888 Y88b.       X88
  106.     8888888888   Y88P    "Y8888  888  888  "Y888  88888P'
  107.    
  108.     ---------------------------------------------------------------------------------------------------
  109.         Signal      Particle.Changed(string propertyName, Variant newValue)
  110.                     Fires when one of the Particles properties are changed.
  111.     ---------------------------------------------------------------------------------------------------
  112.         Signal      Particle.Destroyed()
  113.                     Fires when the particle is destroyed.
  114.     ---------------------------------------------------------------------------------------------------
  115.                                                                                                                                    --]]
  116. ---------------------------------------------------------------------------------------------------------------------------------------
  117. -- Begin Particle Codebase
  118. ---------------------------------------------------------------------------------------------------------------------------------------
  119.  
  120. if game:FindService("NetworkServer") then
  121.     error("Particle library can only be used by LocalScripts.",0)
  122. end
  123.  
  124. local Particle = {}
  125.  
  126. local PUBLIC_MEMBERS =
  127. {
  128.     CFrame = CFrame.new();
  129.     Color = Color3.new(1,1,1);
  130.     Enabled = true;
  131.     FaceCamera = true;
  132.     LightEmission = 1;
  133.     Orientation = Vector3.new();
  134.     Position = Vector3.new();
  135.     Rotation = 0;
  136.     Scale = Vector3.new(1,1,0);
  137.     Size = Vector2.new(1,1);
  138.     Texture = "rbxasset://textures/particles/sparkles_main.dds";
  139.     Transparency = 0;
  140.     ZOffset = 0;
  141. }
  142.  
  143. local push = table.insert
  144. local pop = table.remove
  145.  
  146. local node = Instance.new("Part")
  147. node.Name = "ParticleNode"
  148. node.Anchored = true
  149. node.CanCollide = false
  150. node.Transparency = 1
  151. node.Locked = true
  152.  
  153. local particleRegistry = {}
  154.  
  155. local function getState(particle)
  156.     local state = particleRegistry[particle]
  157.     assert(state, "This particle has been destroyed!")
  158.     return state
  159. end
  160.  
  161. local function assertMember(index)
  162.     assert(PUBLIC_MEMBERS[index], tostring(index) .. " is not a valid member of Particle.")
  163. end
  164.  
  165. local function markDirty(state,member)
  166.     if not state.Private.PendingClean[member] then
  167.         state.Private.PendingClean[member] = true
  168.         push(state.Private.Dirty,member)
  169.     end
  170. end
  171.  
  172. local function setValue(state,member,new)
  173.     markDirty(state,member)
  174.     state.Public[member] = new
  175. end
  176.  
  177. local function tupled(func,...)
  178.     local results = {}
  179.     for i,arg in ipairs{...} do
  180.         results[i] = func(arg)
  181.     end
  182.     return unpack(results)
  183. end
  184.  
  185. ------------------------------------------------------------------------------------------------------------------------------------------
  186. -- API Declarations
  187. ------------------------------------------------------------------------------------------------------------------------------------------
  188.  
  189. local api =
  190. {
  191.     Methods = {};
  192.     Bridge = {};
  193. }
  194.  
  195. local newIndexErrorMsg = "Expected %s when setting Particle.%s (got %s)"
  196.  
  197. function api.Methods:Clone()
  198.     local newParticle = Particle.new()
  199.     local state = getState(self)
  200.    
  201.     for member,value in pairs(state.Public) do
  202.         newParticle[member] = value
  203.     end
  204.    
  205.     return newParticle
  206. end
  207.  
  208. function api.Methods:MakeExternalBin()
  209.     local state = getState(self)
  210.     local modifier = Instance.new("Folder")
  211.     modifier.Name = "Particle"
  212.    
  213.     for propName,default in pairs(PUBLIC_MEMBERS) do
  214.         local t = typeof(default)
  215.         if t == "boolean" then t = "bool" end
  216.        
  217.         local className = t:gsub("^.",string.upper) .. "Value"
  218.         local success,value = pcall(Instance.new,className)
  219.        
  220.         if success and value then
  221.             local updater = self:GetPropertyChangedSignal(propName)
  222.            
  223.             local function updateValue()
  224.                 value.Value = self[propName]
  225.             end
  226.            
  227.             local function onValueChanged(newValue)
  228.                 if self[propName] ~= newValue then
  229.                     self[propName] = newValue
  230.                 end
  231.             end
  232.            
  233.             value.Name = propName
  234.             value.Parent = modifier
  235.            
  236.             updateValue()
  237.             updater:Connect(updateValue)
  238.             value.Changed:connect(onValueChanged)
  239.         end
  240.     end
  241.    
  242.     local function onDestroyed()
  243.         modifier:Destroy()
  244.     end
  245.    
  246.     self.Destroyed:Connect(onDestroyed)
  247.     return modifier
  248. end
  249.  
  250. function api.Methods:Destroy()
  251.     local state = particleRegistry[self]
  252.     if state then
  253.         state.Private.Beam:Destroy()
  254.         state.Private.A0:Destroy()
  255.         state.Private.A1:Destroy()
  256.         state.Private.Events.Destroyed:Fire()
  257.     end
  258.     particleRegistry[self] = nil
  259. end
  260.  
  261. function api.Methods:GetPropertyChangedSignal(property)
  262.     local state = getState(self)
  263.     assertMember(property)
  264.    
  265.     local signal = Instance.new("BindableEvent")
  266.    
  267.     local function onChanged(name,value)
  268.         if name == property then
  269.             signal:Fire(value)
  270.         end
  271.     end
  272.    
  273.     self.Changed:Connect(onChanged)
  274.     return signal.Event
  275. end
  276.  
  277. function api.Bridge:__index(member)
  278.     local state = getState(self)
  279.     if api.Methods[member] then
  280.         return api.Methods[member]
  281.     elseif state.Private.Events[member] then
  282.         return state.Private.Events[member].Event
  283.     else
  284.         assertMember(member)
  285.         return state.Public[member]
  286.     end
  287. end
  288.  
  289. function api.Bridge:__newindex(member,new)
  290.     local state = getState(self)
  291.     assertMember(member)
  292.  
  293.     local expectedType = typeof(PUBLIC_MEMBERS[member])
  294.     local receivedType = typeof(new)
  295.    
  296.     assert(expectedType == receivedType, newIndexErrorMsg:format(expectedType,member,receivedType))
  297.     setValue(state,member,new)
  298. end
  299.  
  300. ---------------------------------------------------------------------------------------------------------------------------------------
  301. -- Renderstep Updater
  302. ---------------------------------------------------------------------------------------------------------------------------------------
  303.  
  304. local RunService = game:GetService("RunService")
  305.  
  306. local function updateParticles()
  307.     local c = workspace.CurrentCamera
  308.     node.Parent = c
  309.    
  310.     for particle,state in pairs(particleRegistry) do
  311.         local private = state.Private
  312.         local public = state.Public
  313.        
  314.         local beam = private.Beam
  315.         local dirty = private.Dirty
  316.         local pending = private.PendingClean
  317.         local updateCF = false
  318.        
  319.         -- Update any properties that need updating
  320.         while #dirty > 0 do
  321.             local name = pop(dirty)
  322.             local value = public[name]
  323.             if name == "Color" then
  324.                 beam.Color = ColorSequence.new(value)
  325.             elseif name == "Transparency" then
  326.                 beam.Transparency = NumberSequence.new(value)
  327.             elseif name == "CFrame" then
  328.                 updateCF = true
  329.                 if public.Position ~= value.p then
  330.                     setValue(state,"Position",value.p)
  331.                 end
  332.                 local ox,oy,oz = tupled(math.deg,value:toOrientation())
  333.                 local orientation = Vector3.new(ox,oy,oz)
  334.                 if public.Orientation ~= orientation then
  335.                     setValue(state,"Orientation",orientation)
  336.                 end
  337.             elseif name == "Position" then
  338.                 local cf = public.CFrame
  339.                 if cf.p ~= value then
  340.                     setValue(state,"CFrame",CFrame.new(value)*(cf-cf.p))
  341.                 end
  342.                 updateCF = true
  343.             elseif name == "Orientation" then
  344.                 local cf = public.CFrame
  345.                 local pos = cf.p
  346.                 local rot = cf-pos
  347.                 local ox,oy,oz = tupled(math.rad,value.X,value.Y,value.Z)
  348.                 local newRot = CFrame.fromOrientation(ox,oy,oz)
  349.                 if rot ~= newRot then
  350.                     setValue(state,"CFrame",CFrame.new(pos) * newRot)
  351.                 end
  352.                 updateCF = true
  353.             elseif name == "Scale" then
  354.                 updateCF = true
  355.                 beam.Width0 = value.Y
  356.                 beam.Width1 = value.Y
  357.                 beam.ZOffset = value.Z
  358.                 if public.Size.X ~= value.X or public.Size.Y ~= value.Y then
  359.                     setValue(state,"Size",Vector2.new(value.X,value.Y))
  360.                 end
  361.                 if public.ZOffset ~= value.Z then
  362.                     setValue(state,"ZOffset",value.Z)
  363.                 end
  364.             elseif name == "Size" or name == "ZOffset" then
  365.                 local size = public.Size
  366.                 setValue(state,"Scale",Vector3.new(size.X,size.Y,public.ZOffset))
  367.                 updateCF = true
  368.             elseif name == "Rotation" or name == "FaceCamera" then
  369.                 updateCF = true
  370.             elseif name == "Enabled" or name == "LightEmission" or name == "Texture" then
  371.                 beam[name] = value
  372.             end
  373.             private.Events.Changed:Fire(name,value)
  374.             pending[name] = nil
  375.         end
  376.        
  377.         -- Check if we need to update the particle.
  378.         if public.Enabled and public.Transparency < 1 and (updateCF or public.FaceCamera) then
  379.             local cf = public.CFrame
  380.             -- Apply FaceCamera
  381.             if public.FaceCamera then
  382.                 local pos = cf.p
  383.                 local rot = cf-pos
  384.                 cf = CFrame.new(pos,c.CFrame.p) * rot
  385.             end
  386.            
  387.             -- Apply Rotation
  388.             cf = cf * CFrame.Angles(0,0,math.rad(public.Rotation-90))
  389.            
  390.             -- Apply Size
  391.             local width = public.Size.X
  392.             private.A0.CFrame = cf * CFrame.new(-width/2,0,0)
  393.             private.A1.CFrame = cf * CFrame.new( width/2,0,0)
  394.         end
  395.     end
  396. end
  397.  
  398. RunService:BindToRenderStep("UpdateParticles",201,updateParticles)
  399.  
  400. ---------------------------------------------------------------------------------------------------------------------------------------
  401. -- Constructor Function
  402. ---------------------------------------------------------------------------------------------------------------------------------------
  403. local counter = 0
  404.  
  405. function Particle.new()
  406.     local particle = {}
  407.    
  408.     local state =
  409.     {
  410.         Public = {};
  411.         Private =
  412.         {
  413.             Dirty = {};
  414.             PendingClean = {};
  415.             Events =
  416.             {
  417.                 Changed = Instance.new("BindableEvent");
  418.                 Destroyed = Instance.new("BindableEvent");
  419.             };
  420.         };
  421.     }
  422.    
  423.     local name = "Particle" .. tostring(counter)
  424.     counter = counter + 1
  425.    
  426.     local beam = Instance.new("Beam")
  427.     beam.Name = name .. "_Beam"
  428.     beam.Segments = 1
  429.     beam.TextureSpeed = 0
  430.     beam.Parent = node
  431.     state.Private.Beam = beam
  432.    
  433.     local a0 = Instance.new("Attachment")
  434.     a0.Name = name .. "_Att0"
  435.     a0.Parent = node
  436.     beam.Attachment0 = a0
  437.     state.Private.A0 = a0
  438.    
  439.     local a1 = Instance.new("Attachment")
  440.     a1.Name = name .. "_Att1"
  441.     a1.Parent = node
  442.     beam.Attachment1 = a1
  443.     state.Private.A1 = a1
  444.  
  445.     -- Initialize all members, and subsequently mark them as dirty so the effect will update.
  446.     for member,value in pairs(PUBLIC_MEMBERS) do
  447.         setValue(state,member,value)
  448.     end
  449.  
  450.     -- Register this particle to be updated
  451.     setmetatable(particle,api.Bridge)
  452.     particleRegistry[particle] = state
  453.    
  454.     return particle
  455. end
  456.  
  457. return Particle
  458.  
  459. ---------------------------------------------------------------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement