feat: Add Easing functions

This commit is contained in:
Qwreey 2022-12-28 06:37:07 +09:00
parent e10170958a
commit 3318270c3d
5 changed files with 235 additions and 92 deletions

View file

@ -0,0 +1,4 @@
라이브러리 사용법
...작성해야함

View file

@ -155,8 +155,17 @@ function module.init(shared)
local with = value.wfunc; local with = value.wfunc;
local tstore = value.store; local tstore = value.store;
local rawKey = value.key; local rawKey = value.key;
local tween = value.tvalue;
local from = value.fvalue;
local add = value.avalue;
local set = tstore[rawKey]; local set = tstore[rawKey];
if set ~= nil or (rawKey:match(",") and with) then if set ~= nil or (rawKey:match(",") and with) then
if add then
set = set + add;
end
if from then
set = from[set];
end
if with then if with then
set = with(tstore,set,value.key,item); set = with(tstore,set,value.key,item);
end end
@ -167,9 +176,6 @@ function module.init(shared)
setProperty(item,index,dset,ClassName); setProperty(item,index,dset,ClassName);
end end
end end
local tween = value.tvalue;
local from = value.fvalue;
local add = value.avalue;
-- adding event function -- adding event function
local function regFn(_,newValue,key) local function regFn(_,newValue,key)

View file

@ -1,23 +1,5 @@
local EasingFunctions = {} local EasingFunctions = {}
local function reverse(Index)
return 1 - Index
end
local Linear = {} do
Linear.Run = function(Index)
return Index
end
end
EasingFunctions["Linear"] = Linear
local Circle = {} do
Circle.Run = function(Index)
return 1-((1-Index)^2)
end
end
EasingFunctions["Circle"] = Circle
local Exp2 = {} do local Exp2 = {} do
local MinIndex = -4 local MinIndex = -4
local MaxIndex = 2 local MaxIndex = 2
@ -25,13 +7,14 @@ local Exp2 = {} do
return Index * (MaxIndex - MinIndex) + MinIndex return Index * (MaxIndex - MinIndex) + MinIndex
end end
local Min = math.exp(MinIndex) local exp = math.exp
local Max = math.exp(MaxIndex) - Min local Min = exp(MinIndex)
local Max = exp(MaxIndex) - Min
Exp2.Reverse = true Exp2.Reverse = true
Exp2.Run = function(Index) Exp2.Run = function(Index)
-- Index ; max = 1 min = 0 -- Index ; max = 1 min = 0
return (math.exp(GetIndex(Index)) - Min) / Max return (exp(GetIndex(Index)) - Min) / Max
end end
end end
EasingFunctions["Exp2"] = Exp2 EasingFunctions["Exp2"] = Exp2
@ -43,33 +26,140 @@ local Exp4 = {} do
return Index * (MaxIndex - MinIndex) + MinIndex return Index * (MaxIndex - MinIndex) + MinIndex
end end
local Min = math.exp(MinIndex) local exp = math.exp
local Max = math.exp(MaxIndex) - Min local Min = exp(MinIndex)
local Max = exp(MaxIndex) - Min
Exp4.Reverse = true Exp4.Reverse = true
Exp4.Run = function(Index) Exp4.Run = function(Index)
-- Index ; max = 1 min = 0 -- Index ; max = 1 min = 0
return (math.exp(GetIndex(Index)) - Min) / Max return (exp(GetIndex(Index)) - Min) / Max
end end
end end
EasingFunctions["Exp4"] = Exp4 EasingFunctions["Exp4"] = Exp4
local Exp2Max4 = {} do local Linear = {} do
local MinIndex = -2 Linear.Reverse = false
local MaxIndex = 4 Linear.Run = function(Index)
local GetIndex = function(Index) return Index
return Index * (MaxIndex - MinIndex) + MinIndex
end
local Min = math.exp(MinIndex)
local Max = math.exp(MaxIndex) - Min
Exp2Max4.Reverse = true
Exp2Max4.Run = function(Index)
-- Index ; max = 1 min = 0
return (math.exp(GetIndex(Index)) - Min) / Max
end end
end end
EasingFunctions["Exp2Max4"] = Exp2Max4 EasingFunctions["Linear"] = Linear
local Expo = {} do
Expo.Reverse = false
Expo.Run = function(Index)
if Index == 1 then return 1 end
if Index == 0 then return 0 end
return 1 - 2^(-10 * Index)
end
end
EasingFunctions["Expo"] = Expo
local Quint = {} do
Quint.Reverse = false
Quint.Run = function(Index)
if Index == 1 then return 1 end
if Index == 0 then return 0 end
return 1 - ((1 - Index)^5)
end
end
EasingFunctions["Quint"] = Quint
local Quart = {} do
Quart.Reverse = false
Quart.Run = function(Index)
if Index == 1 then return 1 end
if Index == 0 then return 0 end
return 1 - ((1 - Index)^4)
end
end
EasingFunctions["Quart"] = Quart
local Cubic = {} do
Cubic.Reverse = false
Cubic.Run = function(Index)
if Index == 1 then return 1 end
if Index == 0 then return 0 end
return 1 - ((1 - Index)^3)
end
end
EasingFunctions["Cubic"] = Cubic
local Quad = {} do
Quad.Reverse = false
Quad.Run = function(Index)
if Index == 1 then return 1 end
if Index == 0 then return 0 end
return 1 - ((1 - Index)^2)
end
end
EasingFunctions["Quad"] = Quad
local Sin = {} do
local pi2 = math.pi/2
local sin = math.sin
Sin.Reverse = false
Sin.Run = function(Index)
if Index == 1 then return 1 end
if Index == 0 then return 0 end
return sin(Index * pi2);
end
end
EasingFunctions["Sin"] = Sin
local Circle = {} do
local sqrt = math.sqrt
Circle.Run = function(Index)
if Index == 1 then return 1 end
if Index == 0 then return 0 end
return sqrt(1-(1-Index)^2)
end
end
EasingFunctions["Circle"] = Circle
local Back = {} do
local c1 = 1.70158
local c3 = 2.70158
Back.Reverse = false
Back.Run = function(Index)
if Index == 1 then return 1 end
if Index == 0 then return 0 end
return 1 + c3 * (Index-1)^3 + c1 * (Index-1)^2
end
end
EasingFunctions["Back"] = Back
local Elastic = {} do
local sin = math.sin
local pi = math.pi
Elastic.Reverse = false
Elastic.Run = function(Index)
if Index == 1 then return 1 end
if Index == 0 then return 0 end
return (2^(-10*Index))*(sin((Index*10-0.75)*(2*pi/3)))+1
end
end
EasingFunctions["Elastic"] = Elastic
local Bounce = {} do
local n1 = 7.5625
local d1 = 2.75
Bounce.Reverse = false
Bounce.Run = function(Index)
if Index > 0.995 then return 1 end
if Index < 0.005 then return 0 end
if Index < 1 / d1 then
return n1 * Index^2
elseif Index < 2 / d1 then
return n1 * (Index - 1.5/d1)^2 + 0.75
elseif Index < 2.5 / d1 then
return n1 * (Index - 2.25/d1)^2 + 0.9375
else
return n1 * (Index - 2.625/d1)^2 + 0.984375
end
end
end
EasingFunctions["Bounce"] = Bounce
return EasingFunctions return EasingFunctions

View file

@ -9,15 +9,27 @@ local IsRoblox = version and version() or nil
local module = {} local module = {}
function module.BindStep(StepFunction) function module.BindStep(StepFunction)
if IsRoblox then if IsRoblox then
if module.Connection then
error("Function was binded already")
end
local RunService = game:GetService("RunService") local RunService = game:GetService("RunService")
if RunService:IsStudio() and (not RunService:IsRunning()) and RunService:IsEdit() then if RunService:IsStudio() and (not RunService:IsRunning()) and RunService:IsEdit() then
RunService.Heartbeat:Connect(StepFunction) module.Connection = RunService.Heartbeat:Connect(StepFunction)
else else
RunService.Stepped:Connect(StepFunction) -- RunService:BindToRenderStep("advancedTween",1,StepFunction)
module.Connection = RunService.RenderStepped:Connect(StepFunction)
end end
else else
-- do something here -- do something here
end end
end end
function module.UnbindAll()
if not module.Connection then
error("Function was not binded yet")
end
module.Connection:Disconnect()
module.Connection = nil
end
return module return module

View file

@ -16,6 +16,7 @@ local EasingFunctions = require(script and script.EasingFunctions or "EasingFunc
local Stepped = require(script and script.Stepped or "Stepped") local Stepped = require(script and script.Stepped or "Stepped")
local BindedFunctions = {} -- 애니메이션을 위해 프레임에 연결된 함수들 local BindedFunctions = {} -- 애니메이션을 위해 프레임에 연결된 함수들
local FunctionTargetItem = setmetatable({},{__mode="kv"}) -- 함수가 타겟으로 하는 아이템
module.PlayIndex = setmetatable({},{__mode = "k"}) -- 애니메이션 실행 스택 저장하기 module.PlayIndex = setmetatable({},{__mode = "k"}) -- 애니메이션 실행 스택 저장하기
-- PlayIndex[Item][Property] = 0 or nil <= 트윈중이지 않은 속성 -- PlayIndex[Item][Property] = 0 or nil <= 트윈중이지 않은 속성
@ -25,12 +26,21 @@ module.PlayIndex = setmetatable({},{__mode = "k"}) -- 애니메이션 실행 스
-- Easing 스타일 -- Easing 스타일
------------------------------------ ------------------------------------
module.EasingFunctions = { module.EasingFunctions = {
--// for Autocomplete Linear = EasingFunctions.Linear; ---직선, Linear. i=x, x=0 ~ 1
Linear = EasingFunctions.Linear; --// 직선 Quint = EasingFunctions.Quint; ---5제곱, Quint. (^5) i=1-(1-x)^5, x=0 ~ 1
Circle = EasingFunctions.Circle; --// 사분원 Quart = EasingFunctions.Quart; ---4제곱, Quart. (^4) i=1-(1-x)^4, x=0 ~ 1
Exp2 = EasingFunctions.Exp2; --// 덜 가파른 지수 그래프 Cubic = EasingFunctions.Cubic; ---3제곱, Cubic. (^3) i=1-(1-x)^3, x=0 ~ 1
Exp4 = EasingFunctions.Exp4; --// 더 가파른 지수 그래프 Quad = EasingFunctions.Quad; ---2제곱, Quad. (^2) i=1-(1-x)^2, x=0 ~ 1
Exp2Max4 = EasingFunctions.Exp2Max4; --// 적당히 가파른 지수 그래프 Sin = EasingFunctions.Sin; ---사인파, Sin. i=sin(x*pi/2), x=0 ~ 1
Circle = EasingFunctions.Circle; ---사분원, Circle. i=sqrt(1-(1-x)^2), x=0 ~ 1
Expo = EasingFunctions.Expo; ---지수함수, Expo. i=1-2^(-10*x), x=0~1
Elastic = EasingFunctions.Elastic; ---튀어오름, Elastic.
Bounce = EasingFunctions.Bounce; ---통통거림, Bounce
-- Old things
Exp2 = EasingFunctions.Exp2; ---덜 가파른 지수. i=math.exp(x), x=-4 ~ 2
Exp4 = EasingFunctions.Exp4; ---더 가파른 지수. i=math.exp(x), x=-4 ~ 4
Exp2Max4 = EasingFunctions.Exp2; ---@deprecated
} }
for i,v in pairs(EasingFunctions) do for i,v in pairs(EasingFunctions) do
module.EasingFunctions[i] = v module.EasingFunctions[i] = v
@ -78,21 +88,21 @@ function LerpProperties(Item,Old,New,Alpha,Setter)
) )
) )
elseif DefaultItems[Type] then elseif DefaultItems[Type] then
Item[Property] = Lerp(OldValue,NewValue,Alpha) Value = Lerp(OldValue,NewValue,Alpha)
elseif Type == "UDim2" then elseif Type == "UDim2" then
Item[Property] = UDim2.new( Value = UDim2.new(
Lerp(OldValue.X.Scale ,NewValue.X.Scale ,Alpha), Lerp(OldValue.X.Scale ,NewValue.X.Scale ,Alpha),
Lerp(OldValue.X.Offset,NewValue.X.Offset,Alpha), Lerp(OldValue.X.Offset,NewValue.X.Offset,Alpha),
Lerp(OldValue.Y.Scale ,NewValue.Y.Scale ,Alpha), Lerp(OldValue.Y.Scale ,NewValue.Y.Scale ,Alpha),
Lerp(OldValue.Y.Offset,NewValue.Y.Offset,Alpha) Lerp(OldValue.Y.Offset,NewValue.Y.Offset,Alpha)
) )
elseif Type == "UDim" then elseif Type == "UDim" then
Item[Property] = UDim.new( Value = UDim.new(
Lerp(OldValue.Scale ,NewValue.Scale ), Lerp(OldValue.Scale ,NewValue.Scale ),
Lerp(OldValue.Offset,NewValue.Offset) Lerp(OldValue.Offset,NewValue.Offset)
) )
elseif Type == "Color3" then elseif Type == "Color3" then
Item[Property] = Color3.fromRGB( Value = Color3.fromRGB(
Lerp(OldValue.r*255,NewValue.r*255), Lerp(OldValue.r*255,NewValue.r*255),
Lerp(OldValue.g*255,NewValue.g*255), Lerp(OldValue.g*255,NewValue.g*255),
Lerp(OldValue.b*255,NewValue.b*255) Lerp(OldValue.b*255,NewValue.b*255)
@ -108,7 +118,7 @@ function LerpProperties(Item,Old,New,Alpha,Setter)
) )
end end
if Setter then if Setter then
Setter(Item,Property,NewValue) Setter(Item,Property,Value)
else else
Item[Property] = Value Item[Property] = Value
end end
@ -139,20 +149,32 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_)
local EndTime = clock() + Time local EndTime = clock() + Time
-- 플레이 인덱스 저장 -- 플레이 인덱스 저장
local ThisPlayIndex = module.PlayIndex[Item] or {} local ItemPlayIndex = module.PlayIndex[Item]
module.PlayIndex[Item] = ThisPlayIndex if ItemPlayIndex then
for _,stepFunc in ipairs(BindedFunctions) do
-- 예전의 트윈을 덮어쓰고 현재 값을 저장함 if FunctionTargetItem[stepFunc] == Item then
local NowAnimationIndex = {} stepFunc() -- 해당 애니메이션을 미리 계산해서 지금 위치를 저장
local LastProperties = {} end
for Property,_ in pairs(Properties) do
if Getter then
LastProperties[Property] = Getter(Property)
else
LastProperties[Property] = Item[Property]
end end
ThisPlayIndex[Property] = ThisPlayIndex[Property] ~= nil and ThisPlayIndex[Property] + 1 or 1 ItemPlayIndex = module.PlayIndex[Item]
NowAnimationIndex[Property] = ThisPlayIndex[Property] end
if not ItemPlayIndex then
ItemPlayIndex = {}
module.PlayIndex[Item] = ItemPlayIndex
end
-- 예전의 트윈을 덮어쓰고 현재 값을 저장함 !이전 트윈은 파기됨
local ThisPlayIndex = {}
local LastProperties = {}
for PropertyName,_ in pairs(Properties) do
if Getter then
LastProperties[PropertyName] = Getter(Item,PropertyName)
else
LastProperties[PropertyName] = Item[PropertyName]
end
local PlayIndex = (ItemPlayIndex[PropertyName] or 0) + 1
ItemPlayIndex[PropertyName] = PlayIndex
ThisPlayIndex[PropertyName] = PlayIndex
end end
-- 이징 효과 가져오기 -- 이징 효과 가져오기
@ -160,6 +182,10 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_)
local Easing do local Easing do
local Data_Easing = Data.Easing or EasingFunctions.Exp2 local Data_Easing = Data.Easing or EasingFunctions.Exp2
local Data_EasingType = type(Data_Easing) local Data_EasingType = type(Data_Easing)
if Data_EasingType == "string" then
Data_Easing = EasingFunctions[Data_Easing]
Data_EasingType = "table"
end
Easing = (Data_EasingType == "function" and Data_Easing) or (Data_EasingType == "table" and Data_Easing.Run) Easing = (Data_EasingType == "function" and Data_Easing) or (Data_EasingType == "table" and Data_Easing.Run)
if Data_EasingType == "table" and Data_Easing.Reverse then if Data_EasingType == "table" and Data_Easing.Reverse then
Direction = Direction == "Out" and "In" or "Out" Direction = Direction == "Out" and "In" or "Out"
@ -171,11 +197,15 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_)
if CallBack then if CallBack then
for FncIndex,Fnc in pairs(CallBack) do for FncIndex,Fnc in pairs(CallBack) do
if type(Fnc) ~= "function" or (type(tonumber(FncIndex)) ~= "number" and FncIndex ~= "*") then if type(Fnc) ~= "function" or (type(tonumber(FncIndex)) ~= "number" and FncIndex ~= "*") then
warn(("Unprocessable callback function got, Ignored.\n - key: %s value: %s"):format(tostring(Fnc),tostring(FncIndex))) warn(
("Unprocessable callback function got, Ignored.\n - key: %s value: %s")
:format(tostring(Fnc),tostring(FncIndex))
)
CallBack[FncIndex] = nil CallBack[FncIndex] = nil
end end
end end
end end
-- 스탭핑 -- 스탭핑
local Step local Step
Step = function() Step = function()
@ -185,6 +215,18 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_)
return return
end end
-- 다른 트윈이 속성을 바꾸고 있다면(이후 트윈이) 그 속성을 건들지 않도록 없엠
local StopByOther = true
for PropertyName,PlayIndex in pairs(ThisPlayIndex) do
if PlayIndex ~= ItemPlayIndex[PropertyName] then
LastProperties[PropertyName] = nil
Properties[PropertyName] = nil
ThisPlayIndex[PropertyName] = nil
else
StopByOther = false
end
end
local Now = clock() local Now = clock()
local Index = 1 - (EndTime - Now) / Time local Index = 1 - (EndTime - Now) / Time
local Alpha = Direction == "Out" and Easing(Index) or (1 - Easing(1 - Index)) local Alpha = Direction == "Out" and Easing(Index) or (1 - Easing(1 - Index))
@ -198,18 +240,6 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_)
Setter Setter
) )
-- 다른 트윈이 속성을 바꾸고 있다면(이후 트윈이) 그 속성을 건들지 않도록 없엠
local StopByOther = true
for Property,Index in pairs(NowAnimationIndex) do
if Index ~= ThisPlayIndex[Property] then
LastProperties[Property] = nil
Properties[Property] = nil
NowAnimationIndex[Property] = nil
else
StopByOther = false
end
end
-- 만약 다른 트윈이 지금 트윈하고 있는 속성을 모두 먹은경우 현재 트윈을 삭제함 -- 만약 다른 트윈이 지금 트윈하고 있는 속성을 모두 먹은경우 현재 트윈을 삭제함
if StopByOther then if StopByOther then
remove(BindedFunctions,find(BindedFunctions,Step)) remove(BindedFunctions,find(BindedFunctions,Step))
@ -219,15 +249,11 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_)
-- 끝남 -- 끝남
if Now >= EndTime then if Now >= EndTime then
for Property,_ in pairs(Properties) do for Property,_ in pairs(Properties) do
ThisPlayIndex[Property] = 0 ItemPlayIndex[Property] = 0
end end
local PlayIndexLen = 0 if next(ItemPlayIndex) then
for _,_ in pairs(ThisPlayIndex) do module.PlayIndex[Item] = nil
PlayIndexLen = PlayIndexLen + 1
end
if PlayIndexLen == 0 then
ThisPlayIndex = nil
end end
remove(BindedFunctions,find(BindedFunctions,Step)) remove(BindedFunctions,find(BindedFunctions,Step))
@ -264,6 +290,7 @@ function module.RunTween(Item,Data,Properties,Ended,OnStepped,Setter,Getter,_)
-- 스캐줄에 등록 -- 스캐줄에 등록
insert(BindedFunctions,Step) insert(BindedFunctions,Step)
FunctionTargetItem[Step] = Item
end end
-- 여러개의 개체를 트윈시킴 -- 여러개의 개체를 트윈시킴
@ -319,13 +346,17 @@ end
-- ./Stepped.lua 에서 연결점 편집 가능 -- ./Stepped.lua 에서 연결점 편집 가능
-- roblox 는 이미 연결되어 있음 -- roblox 는 이미 연결되어 있음
function module.Stepped() function module.Stepped()
if not BindedFunctions[1] then
return;
end
for _,Function in ipairs(BindedFunctions) do for _,Function in ipairs(BindedFunctions) do
Function() if not FunctionTargetItem[Function] then
remove(BindedFunctions,find(BindedFunctions,Function))
else
Function()
end
end end
end end
Stepped.BindStep(module.Stepped) Stepped.BindStep(module.Stepped)
script.Destroying:Connect(function()
Stepped.UnbindAll()
end)
return module return module