So, today I thought it would be cool to make a module script to get the value and envelope of a given time of a NumberSequence.
Then I came up with the idea for making “particles” that will go to given points.
So for the past hour, I worked a part based system and BillboardGui based system. Both operate at about 58 FPS for me.
I have also open sourced this code for anyone to optimize, change, add on to, or implement to anything.
Open sourced place: Math Based Particles - Roblox
Spline module:
[code]–Module made by me to get the value of a spline curve when given a time.
local Module = {}
function Module:Load(Numbersequence)
local Curve = {}
local Points = {}
local Numbers = {}
for _,Point in pairs(Numbersequence.Keypoints) do
table.insert(Numbers,Point.Time)
local Envelope = Point.Envelope
local ScaleUp = 0
if Envelope > 0 then
ScaleUp = math.random(-Envelope100,Envelope100)/100
end
Points[Point.Time] = Point.Value + ScaleUp
end
local function GetNextLowerNumber(Number)
local LowestNumber,Dif
for i = 1, #Numbers do
if Numbers[i] <= Number then
if not Dif then
LowestNumber,Dif = Numbers[i],Number - Numbers[i]
elseif Dif > Number - Numbers[i] then
LowestNumber,Dif = Numbers[i],Number - Numbers[i]
end
end
end
return LowestNumber or 0
end
local function GetNextHigherNumber(Number)
local HighestNumber,Dif
for i = 1, #Numbers do
if Numbers[i] >= Number then
if not Dif then
HighestNumber,Dif = Numbers[i],Numbers[i] - Number
elseif Dif > Numbers[i] - Number then
HighestNumber,Dif = Numbers[i],Numbers[i] - Number
end
end
end
return HighestNumber or 1
end
local function Lerp(Min,Max,Ratio)
return Min + (Max - Min)*Ratio
end
function Curve:Get(Time)
local LowerNumber = GetNextLowerNumber(Time)
local HigherNumber = GetNextHigherNumber(Time)
local Percent = 1 - (HigherNumber - Time)/(HigherNumber - LowerNumber)
if tostring(Percent) == "-1.#IND" then Percent = 1 end
local MinValue,MaxValue = Points[LowerNumber],Points[HigherNumber]
return Lerp(MinValue,MaxValue,Percent)
end
return Curve
end
return Module[/code]
Part based:
[code]–Points the particles go to
local Points = {Vector3.new(0,10,-20),Vector3.new(0,20,-20),Vector3.new(20,10,0),Vector3.new(20,30,-40)}
–Properties
local ColorR = NumberSequence.new({NumberSequenceKeypoint.new(0,0.75,0.25),NumberSequenceKeypoint.new(0.5,0,0),NumberSequenceKeypoint.new(1,0,0)})
local ColorG = NumberSequence.new({NumberSequenceKeypoint.new(0,0,0),NumberSequenceKeypoint.new(0.5,170/255,0),NumberSequenceKeypoint.new(1,0,0)})
local ColorB = NumberSequence.new({NumberSequenceKeypoint.new(0,0,0),NumberSequenceKeypoint.new(0.5,0,0),NumberSequenceKeypoint.new(1,0.5,0.5)})
local Size = NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.new(0.3,3.5,0),NumberSequenceKeypoint.new(0.5,1,0),NumberSequenceKeypoint.new(0.9,1,0),NumberSequenceKeypoint.new(0.95,6.5,3.5),NumberSequenceKeypoint.new(1,1,0)})
local Transparency = NumberSequence.new({NumberSequenceKeypoint.new(0,0.5,0.25),NumberSequenceKeypoint.new(1,0)})
local Enabled = true
local LifeTime = NumberRange.new(0.5,3)
local Rate = 20
local Speed = NumberRange.new(25,35)
–Main Script
local AdvancedSpline = require(game.Workspace:WaitForChild(“SplineModule”))
local RenderSpeed = 60
local RenderStepped = game[“Run Service”].RenderStepped
local function Wait(Number)
if Number then
wait(Number)
else
RenderStepped:wait()
end
end
local function ReleaseParticle(ColorR,ColorG,ColorB,Size,Transparency,LifeTime,Speed)
LifeTime = math.random(LifeTime.Min100,LifeTime.Max100)/100
Speed = math.random(Speed.Min100,Speed.Max100)/100
local Particle = Instance.new(“Part”)
Particle.FormFactor = “Custom”
Particle.Size = Vector3.new(1,1,1)
Particle.CanCollide = false
Particle.Anchored = true
local CR,CG,CB = AdvancedSpline:Load(ColorR),AdvancedSpline:Load(ColorG),AdvancedSpline:Load(ColorB)
local SizeSequence = AdvancedSpline:Load(Size)
local TransSequence = AdvancedSpline:Load(Transparency)
local Mesh = Instance.new("SpecialMesh")
Mesh.MeshType = "FileMesh"
Mesh.MeshId = "http://www.roblox.com/Asset/?id=9856898"
Mesh.TextureId = "http://www.roblox.com/asset/?ID=1361097"
Mesh.Parent = Particle
spawn(function()
local CurN = 1
local CurPoint,NextPoint = Points[1],Points[2]
local CurRatio,RatioInc = 0
local Length = (CurPoint - NextPoint).magnitude
Particle.Parent = game.Workspace
for i = 1, LifeTime*RenderSpeed do
local TimeRatio = i/(LifeTime*RenderSpeed)
if not RatioInc then
RatioInc = (Speed/RenderSpeed)/Length
end
CurRatio = CurRatio + RatioInc
if CurRatio >= 1 then
if Points[CurN + 2] then
CurPoint = NextPoint
NextPoint = Points[CurN + 2]
CurN = CurN + 1
local LengthLeft = (CurRatio - 1) * Length
Length = (CurPoint - NextPoint).magnitude
CurRatio = LengthLeft/Length
RatioInc = (Speed/RenderSpeed)/Length
end
end
local R,G,B = CR:Get(TimeRatio),CG:Get(TimeRatio),CB:Get(TimeRatio)
Mesh.VertexColor = Vector3.new(R,G,B)
local S = SizeSequence:Get(TimeRatio)
Mesh.Scale = Vector3.new(S,S,S)
local T = TransSequence:Get(TimeRatio)
Particle.Transparency = T
Particle.CFrame = CFrame.new(CurPoint:Lerp(NextPoint,CurRatio))
Wait()
end
Particle:Destroy()
end)
end
while true do
if Enabled == true then
ReleaseParticle(ColorR,ColorG,ColorB,Size,Transparency,LifeTime,Speed)
end
wait(1/Rate)
end[/code]
BillboardGui based:
[code]–Points the particles go to
local Points = {Vector3.new(0,10,20),Vector3.new(0,20,20),Vector3.new(20,10,40),Vector3.new(20,30,0)}
–Properties
local ColorR = NumberSequence.new({NumberSequenceKeypoint.new(0,0.75,0.25),NumberSequenceKeypoint.new(0.5,0,0),NumberSequenceKeypoint.new(1,0,0)})
local ColorG = NumberSequence.new({NumberSequenceKeypoint.new(0,0,0),NumberSequenceKeypoint.new(0.5,170/255,0),NumberSequenceKeypoint.new(1,0,0)})
local ColorB = NumberSequence.new({NumberSequenceKeypoint.new(0,0,0),NumberSequenceKeypoint.new(0.5,0,0),NumberSequenceKeypoint.new(1,0.5,0.5)})
local Size = NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.new(0.3,3.5,0),NumberSequenceKeypoint.new(0.5,1,0),NumberSequenceKeypoint.new(0.96,1,0),NumberSequenceKeypoint.new(0.98,6.5,3.5),NumberSequenceKeypoint.new(1,1,0)})
local Texture = “rbxasset://textures/particles/sparkles_main.dds”
local Transparency = NumberSequence.new({NumberSequenceKeypoint.new(0,0.5,0.25),NumberSequenceKeypoint.new(1,0)})
local Enabled = true
local LifeTime = NumberRange.new(0.5,3)
local Rate = 20
local Rotation = NumberRange.new(0,20)
local RotSpeed = NumberRange.new(10,1080)
local Speed = NumberRange.new(25,35)
–Main Script
local AdvancedSpline = require(game.Workspace:WaitForChild(“SplineModule”))
local RenderSpeed = 60
local RenderStepped = game[“Run Service”].RenderStepped
local function Wait(Number)
if Number then
wait(Number)
else
RenderStepped:wait()
end
end
local function ReleaseParticle(ColorR,ColorG,ColorB,Size,Texture,Transparency,LifeTime,Rotation,RotSpeed,Speed)
if LifeTime.Min ~= LifeTime.Max then LifeTime = math.random(LifeTime.Min100,LifeTime.Max100)/100 else LifeTime = LifeTime.Min end
if Speed.Min ~= Speed.Max then Speed = math.random(Speed.Min100,Speed.Max100)/100 else Speed = Speed.Min end
if Rotation.Min ~= Rotation.Max then Rotation = math.random(Rotation.Min100,Rotation.Max100)/100 else Rotation = Rotation.Min end
if RotSpeed.Min ~= RotSpeed.Max then RotSpeed = math.random(RotSpeed.Min100,RotSpeed.Max100)/100 else RotSpeed = RotSpeed.Min end
local Particle = Instance.new("Part")
Particle.FormFactor = "Custom"
Particle.Size = Vector3.new(1,1,1)
Particle.CanCollide = false
Particle.Anchored = true
Particle.Transparency = 1
local CR,CG,CB = AdvancedSpline:Load(ColorR),AdvancedSpline:Load(ColorG),AdvancedSpline:Load(ColorB)
local SizeSequence = AdvancedSpline:Load(Size)
local TransSequence = AdvancedSpline:Load(Transparency)
local BBG = Instance.new("BillboardGui")
local Image = Instance.new("ImageLabel")
Image.BackgroundTransparency = 1
Image.Image = Texture
Image.Size = UDim2.new(1,0,1,0)
Image.Rotation = Rotation
Image.Parent = BBG
BBG.Parent = Particle
spawn(function()
local CurN = 1
local CurPoint,NextPoint = Points[1],Points[2]
local CurRatio,RatioInc = 0
local Length = (CurPoint - NextPoint).magnitude
Particle.Parent = game.Workspace
for i = 1, LifeTime*RenderSpeed do
local RenderRatio = i/(LifeTime*RenderSpeed)
if not RatioInc then
RatioInc = (Speed/RenderSpeed)/Length
end
CurRatio = CurRatio + RatioInc
if CurRatio >= 1 then
if Points[CurN + 2] then
CurPoint = NextPoint
NextPoint = Points[CurN + 2]
CurN = CurN + 1
local LengthLeft = (CurRatio - 1) * Length
Length = (CurPoint - NextPoint).magnitude
CurRatio = LengthLeft/Length
RatioInc = (Speed/RenderSpeed)/Length
end
end
Image.Rotation = Image.Rotation + (RotSpeed/RenderSpeed)
local R,G,B = CR:Get(RenderRatio),CG:Get(RenderRatio),CB:Get(RenderRatio)
Image.ImageColor3 = Color3.new(R,G,B)
local S = SizeSequence:Get(RenderRatio)
BBG.Size = UDim2.new(S,0,S,0)
local T = TransSequence:Get(RenderRatio)
Image.ImageTransparency = T
Particle.CFrame = CFrame.new(CurPoint:Lerp(NextPoint,CurRatio))
Wait()
end
Particle:Destroy()
end)
end
while true do
if Enabled == true then
ReleaseParticle(ColorR,ColorG,ColorB,Size,Texture,Transparency,LifeTime,Rotation,RotSpeed,Speed)
end
wait(1/Rate)
end[/code]
Edit: Ok, I guess I need to post the purpose. It was to make particles/parts go between given points without the dependency for multiple parts and emitters for each turn.