├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── addon.txt └── lua └── autorun └── tween.lua /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: Jova1106 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Jova1106 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A GMod Lua Tween object 2 | ### Supported Tween Types: 3 | ``` 4 | Number 5 | Vector2 6 | Vector 7 | Color 8 | Angle 9 | BSpline/Bezier Curve 10 | ``` 11 | ## Example Clientside Usage: 12 | ### Regular Tween Object: 13 | ```Lua 14 | local vector2_tween = Tween(Vector2(500, 400), Vector2(700, 500), 1, TWEEN_EASE_QUAD_IN_OUT) 15 | local number_tween = Tween(300, 20, 0.5, TWEEN_EASE_QUAD_OUT) 16 | local vector_tween = Tween(Vector(0,0,0), Vector(100,100,100), 3, TWEEN_EASE_LINEAR) 17 | local color_tween = Tween(Color(255, 25, 35, 80), Color(75, 185, 40, 150), 1, TWEEN_EASE_QUAD_OUT) 18 | 19 | timer.Simple(1.25, function() 20 | vector2_tween:Start() 21 | number_tween:Start() 22 | vector_tween:Start() 23 | color_tween:Start() 24 | end) 25 | 26 | hook.Add("HUDPaint", "draw_2d_tweens", function() 27 | -- Vector2 Tween 28 | local vector2_tween_value = vector2_tween:GetValue() 29 | draw.RoundedBox(0, vector2_tween_value.x, vector2_tween_value.y, 50, 100, Color(255, 0, 0)) 30 | 31 | -- Number Tween 32 | local number_tween_value = number_tween:GetValue() 33 | draw.RoundedBox(0, 500, 650, number_tween_value, 20, Color(255, 0, 0)) 34 | 35 | -- Color Tween 36 | local color_tween_value = color_tween:GetValue() 37 | draw.RoundedBox(0, 500, 700, 100, 20, color_tween_value) 38 | end) 39 | 40 | hook.Add("PostDrawTranslucentRenderables", "draw_3d_tweens", function() 41 | -- Vector Tween 42 | local vector_tween_value = vector_tween:GetValue() 43 | render.SetColorMaterial() 44 | render.DrawSphere(vector_tween_value, 50, 10, 10, Color(255, 0, 0)) 45 | end) 46 | 47 | -- Bezier Tween 48 | function tween.DrawBezier(points, color) 49 | if table.IsEmpty(points) then return end 50 | render.SetColorMaterial() 51 | color = color or color_white 52 | local len = #points 53 | 54 | for i = 1, len do 55 | local p1 = points[i] 56 | local p2 = points[i+1] or points[i] 57 | 58 | if i < len then 59 | render.DrawLine(p1, p2, color, true) 60 | end 61 | 62 | render.DrawSphere(p1, .5, 10, 10, color) 63 | end 64 | end 65 | 66 | local delta = 0.05 67 | local bezier_list = {} 68 | local control_points = { 69 | Vector(0, 0, 0), 70 | Vector(50, 50, 50), 71 | Vector(-100, 100,0), 72 | Vector(150,150,100), 73 | Vector(200,200, -100), 74 | Vector(250, 250, 200), 75 | Vector(300, 300, 0), 76 | Vector(350, 500, 50), 77 | Vector(400, 400, 100) 78 | } 79 | 80 | for i = 0, 1.01, delta do 81 | table.insert(bezier_list, tween.BSpline(control_points, i)) 82 | end 83 | 84 | local bezier_tween = BezierTween(bezier_list, 5, TWEEN_EASE_LINEAR) 85 | 86 | bezier_tween:Start() 87 | 88 | hook.Add("PostDrawTranslucentRenderables", "Bezier3D", function() 89 | tween.DrawBezier(bezier_list) 90 | 91 | local p = bezier_tween:GetValue() 92 | render.SetColorMaterial() 93 | render.DrawSphere(p, 2, 10, 10, color_white) 94 | end) 95 | ``` 96 | 97 | ### TweenUnpacked Object: 98 | ```Lua 99 | local color = Color(255, 0, 0, 255) 100 | local color_tween = TweenUnpacked(color, Color(255, 25, 35), Color(75, 185, 40, 150), 1, TWEEN_EASE_QUAD_OUT) 101 | 102 | timer.Simple(1.25, function() 103 | color_tween:Start() 104 | end) 105 | 106 | hook.Add("HUDPaint", "draw_color_tween", function() 107 | draw.RoundedBox(0, 500, 650, 100, 20, color) 108 | end) 109 | ``` 110 | 111 | Note: Numbers technically work with TweenUnpacked, but since numbers aren't objects, they can't be manipulated in the same way that an object like a Vector can, so if you try to tween a number with TweenUnpacked, you still have to use tween:GetValue(), or just use the regular Tween object. 112 | 113 | ### Ease Types Test: 114 | ```Lua 115 | local color_red = Color(255, 0, 0, 255) 116 | local tween_duration = 3 117 | local TWEEN_EASE_LINEAR_tween = Tween(10, 300, tween_duration, TWEEN_EASE_LINEAR) 118 | local TWEEN_EASE_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_IN_OUT) 119 | local TWEEN_EASE_SINE_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_SINE_IN) 120 | local TWEEN_EASE_SINE_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_SINE_OUT) 121 | local TWEEN_EASE_SINE_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_SINE_IN_OUT) 122 | local TWEEN_EASE_QUAD_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_QUAD_IN) 123 | local TWEEN_EASE_QUAD_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_QUAD_OUT) 124 | local TWEEN_EASE_QUAD_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_QUAD_IN_OUT) 125 | local TWEEN_EASE_CUBIC_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_CUBIC_IN) 126 | local TWEEN_EASE_CUBIC_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_CUBIC_OUT) 127 | local TWEEN_EASE_CUBIC_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_CUBIC_IN_OUT) 128 | local TWEEN_EASE_QUART_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_QUART_IN) 129 | local TWEEN_EASE_QUART_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_QUART_OUT) 130 | local TWEEN_EASE_QUART_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_QUART_IN_OUT) 131 | local TWEEN_EASE_QUINT_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_QUINT_IN) 132 | local TWEEN_EASE_QUINT_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_QUINT_OUT) 133 | local TWEEN_EASE_QUINT_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_QUINT_IN_OUT) 134 | local TWEEN_EASE_EXPO_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_EXPO_IN) 135 | local TWEEN_EASE_EXPO_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_EXPO_OUT) 136 | local TWEEN_EASE_EXPO_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_EXPO_IN_OUT) 137 | local TWEEN_EASE_CIRC_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_CIRC_IN) 138 | local TWEEN_EASE_CIRC_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_CIRC_OUT) 139 | local TWEEN_EASE_CIRC_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_CIRC_IN_OUT) 140 | local TWEEN_EASE_BACK_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_BACK_IN) 141 | local TWEEN_EASE_BACK_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_BACK_OUT) 142 | local TWEEN_EASE_BACK_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_BACK_IN_OUT) 143 | local TWEEN_EASE_ELASTIC_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_ELASTIC_IN) 144 | local TWEEN_EASE_ELASTIC_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_ELASTIC_OUT) 145 | local TWEEN_EASE_ELASTIC_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_ELASTIC_IN_OUT) 146 | local TWEEN_EASE_BOUNCE_IN_tween = Tween(10, 300, tween_duration, TWEEN_EASE_BOUNCE_IN) 147 | local TWEEN_EASE_BOUNCE_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_BOUNCE_OUT) 148 | local TWEEN_EASE_BOUNCE_IN_OUT_tween = Tween(10, 300, tween_duration, TWEEN_EASE_BOUNCE_IN_OUT) 149 | 150 | local tweens = { 151 | {TWEEN_EASE_LINEAR_tween, "TWEEN_EASE_LINEAR"}, 152 | {TWEEN_EASE_IN_OUT_tween, "TWEEN_EASE_IN_OUT"}, 153 | {TWEEN_EASE_SINE_IN_tween, "TWEEN_EASE_SINE_IN"}, 154 | {TWEEN_EASE_SINE_OUT_tween, "TWEEN_EASE_SINE_OUT"}, 155 | {TWEEN_EASE_SINE_IN_OUT_tween, "TWEEN_EASE_SINE_IN_OUT"}, 156 | {TWEEN_EASE_QUAD_IN_tween, "TWEEN_EASE_QUAD_IN"}, 157 | {TWEEN_EASE_QUAD_OUT_tween, "TWEEN_EASE_QUAD_OUT"}, 158 | {TWEEN_EASE_QUAD_IN_OUT_tween, "TWEEN_EASE_QUAD_IN_OUT"}, 159 | {TWEEN_EASE_CUBIC_IN_tween, "TWEEN_EASE_CUBIC_IN"}, 160 | {TWEEN_EASE_CUBIC_OUT_tween, "TWEEN_EASE_CUBIC_OUT"}, 161 | {TWEEN_EASE_CUBIC_IN_OUT_tween, "TWEEN_EASE_CUBIC_IN_OUT"}, 162 | {TWEEN_EASE_QUART_IN_tween, "TWEEN_EASE_QUART_IN"}, 163 | {TWEEN_EASE_QUART_OUT_tween, "TWEEN_EASE_QUART_OUT"}, 164 | {TWEEN_EASE_QUART_IN_OUT_tween, "TWEEN_EASE_QUART_IN_OUT"}, 165 | {TWEEN_EASE_QUINT_IN_tween, "TWEEN_EASE_QUINT_IN"}, 166 | {TWEEN_EASE_QUINT_OUT_tween, "TWEEN_EASE_QUINT_OUT"}, 167 | {TWEEN_EASE_QUINT_IN_OUT_tween, "TWEEN_EASE_QUINT_IN_OUT"}, 168 | {TWEEN_EASE_EXPO_IN_tween, "TWEEN_EASE_EXPO_IN"}, 169 | {TWEEN_EASE_EXPO_OUT_tween, "TWEEN_EASE_EXPO_OUT"}, 170 | {TWEEN_EASE_EXPO_IN_OUT_tween, "TWEEN_EASE_EXPO_IN_OUT"}, 171 | {TWEEN_EASE_CIRC_IN_tween, "TWEEN_EASE_CIRC_IN"}, 172 | {TWEEN_EASE_CIRC_OUT_tween, "TWEEN_EASE_CIRC_OUT"}, 173 | {TWEEN_EASE_CIRC_IN_OUT_tween, "TWEEN_EASE_CIRC_IN_OUT"}, 174 | {TWEEN_EASE_BACK_IN_tween, "TWEEN_EASE_BACK_IN"}, 175 | {TWEEN_EASE_BACK_OUT_tween, "TWEEN_EASE_BACK_OUT"}, 176 | {TWEEN_EASE_BACK_IN_OUT_tween, "TWEEN_EASE_BACK_IN_OUT"}, 177 | {TWEEN_EASE_ELASTIC_IN_tween, "TWEEN_EASE_ELASTIC_IN"}, 178 | {TWEEN_EASE_ELASTIC_OUT_tween, "TWEEN_EASE_ELASTIC_OUT"}, 179 | {TWEEN_EASE_ELASTIC_IN_OUT_tween, "TWEEN_EASE_ELASTIC_IN_OUT"}, 180 | {TWEEN_EASE_BOUNCE_IN_tween, "TWEEN_EASE_BOUNCE_IN"}, 181 | {TWEEN_EASE_BOUNCE_OUT_tween, "TWEEN_EASE_BOUNCE_OUT"}, 182 | {TWEEN_EASE_BOUNCE_IN_OUT_tween, "TWEEN_EASE_BOUNCE_IN_OUT"}, 183 | } 184 | 185 | timer.Simple(1.25, function() 186 | for i = 1, #tweens do 187 | local tween = tweens[i][1] 188 | 189 | tween:Start() 190 | end 191 | end) 192 | 193 | surface.CreateFont( 194 | "TweenTestFont", 195 | 196 | { 197 | size = 15, 198 | weight = 1500, 199 | shadow = true, 200 | } 201 | ) 202 | 203 | concommand.Add("tween_reset_test", function() 204 | for i = 1, #tweens do 205 | local tween = tweens[i][1] 206 | 207 | tween:Stop() 208 | tween.value = tween.from 209 | 210 | timer.Simple(1.25, function() 211 | tween:Start() 212 | end) 213 | end 214 | end) 215 | 216 | hook.Add("DrawOverlay", "tween_ease_types_test", function() 217 | for i = 1, #tweens do 218 | local tween_tbl = tweens[i] 219 | local tween = tween_tbl[1] 220 | local label = tween_tbl[2] 221 | local tween_value = tween:GetValue() 222 | 223 | draw.RoundedBox(0, (ScrW() - 300) / 2, 100 + 20 * i, tween_value, 19, color_red) 224 | draw.SimpleText(label, "TweenTestFont", ScrW() / 2, 100 + 19/2 - 1 + 20 * i, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) 225 | end 226 | end) 227 | ``` -------------------------------------------------------------------------------- /addon.txt: -------------------------------------------------------------------------------- 1 | "AddonInfo" 2 | { 3 | "name" "Lua Tween" 4 | "version" "1.0" 5 | "author_name" "Jova" 6 | "info" "Lua Tween" 7 | "override" "0" 8 | } -------------------------------------------------------------------------------- /lua/autorun/tween.lua: -------------------------------------------------------------------------------- 1 | -- MIT License 2 | 3 | -- Copyright (c) 2022 Jova1106 4 | 5 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 6 | -- of this software and associated documentation files (the "Software"), to deal 7 | -- in the Software without restriction, including without limitation the rights 8 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | -- copies of the Software, and to permit persons to whom the Software is 10 | -- furnished to do so, subject to the following conditions: 11 | 12 | -- The above copyright notice and this permission notice shall be included in all 13 | -- copies or substantial portions of the Software. 14 | 15 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | -- SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- 24 | 25 | if tween then return end 26 | 27 | tween = {} 28 | 29 | local isfunction = isfunction 30 | local math_fmod = math.fmod 31 | local math_pow = math.pow 32 | local Vector_0 = Vector(0, 0, 0) 33 | 34 | TWEEN_EASE_LINEAR = function(n) return n end 35 | TWEEN_EASE_IN_OUT = math.EaseInOut 36 | TWEEN_EASE_SINE_IN = math.ease.InSine 37 | TWEEN_EASE_SINE_OUT = math.ease.OutSine 38 | TWEEN_EASE_SINE_IN_OUT = math.ease.InOutSine 39 | TWEEN_EASE_QUAD_IN = math.ease.InQuad 40 | TWEEN_EASE_QUAD_OUT = math.ease.OutQuad 41 | TWEEN_EASE_QUAD_IN_OUT = math.ease.InOutQuad 42 | TWEEN_EASE_CUBIC_IN = math.ease.InCubic 43 | TWEEN_EASE_CUBIC_OUT = math.ease.OutCubic 44 | TWEEN_EASE_CUBIC_IN_OUT = math.ease.InOutCubic 45 | TWEEN_EASE_QUART_IN = math.ease.InQuart 46 | TWEEN_EASE_QUART_OUT = math.ease.OutQuart 47 | TWEEN_EASE_QUART_IN_OUT = math.ease.InOutQuart 48 | TWEEN_EASE_QUINT_IN = math.ease.InQuint 49 | TWEEN_EASE_QUINT_OUT = math.ease.OutQuint 50 | TWEEN_EASE_QUINT_IN_OUT = math.ease.InOutQuint 51 | TWEEN_EASE_EXPO_IN = math.ease.InExpo 52 | TWEEN_EASE_EXPO_OUT = math.ease.OutExpo 53 | TWEEN_EASE_EXPO_IN_OUT = math.ease.InOutExpo 54 | TWEEN_EASE_CIRC_IN = math.ease.InCirc 55 | TWEEN_EASE_CIRC_OUT = math.ease.OutCirc 56 | TWEEN_EASE_CIRC_IN_OUT = math.ease.InOutCirc 57 | TWEEN_EASE_BACK_IN = math.ease.InBack 58 | TWEEN_EASE_BACK_OUT = math.ease.OutBack 59 | TWEEN_EASE_BACK_IN_OUT = math.ease.InOutBack 60 | TWEEN_EASE_ELASTIC_IN = math.ease.InElastic 61 | TWEEN_EASE_ELASTIC_OUT = math.ease.OutElastic 62 | TWEEN_EASE_ELASTIC_IN_OUT = math.ease.InOutElastic 63 | TWEEN_EASE_BOUNCE_IN = math.ease.InBounce 64 | TWEEN_EASE_BOUNCE_OUT = math.ease.OutBounce 65 | TWEEN_EASE_BOUNCE_IN_OUT = math.ease.InOutBounce 66 | 67 | local function table_Inherit(target, base) 68 | for k, v in next, base do 69 | if target[k] then continue end 70 | 71 | target[k] = v 72 | end 73 | 74 | return target 75 | end 76 | 77 | local metaTable_Vector2 = { 78 | __add = function(self, other) 79 | return Vector2(self.x + other.x, self.y + other.y) 80 | end, 81 | 82 | __sub = function(self, other) 83 | return Vector2(self.x - other.x, self.y - other.y) 84 | end, 85 | 86 | __mul = function(self, other) 87 | if isnumber(other) then 88 | return Vector2(self.x * other, self.y * other) 89 | elseif isnumber(self) then 90 | return Vector2(self * other.x, self * other.y) 91 | end 92 | 93 | return Vector2(self.x * other.x, self.y * other.y) 94 | end, 95 | 96 | __div = function(self, other) 97 | if isnumber(other) then 98 | return Vector2(self.x / other, self.y / other) 99 | end 100 | 101 | return Vector2(self.x / other.x, self.y / other.y) 102 | end, 103 | 104 | __tostring = function(self) 105 | return string.format("%.6f %.6f", self.x, self.y) 106 | end, 107 | 108 | SetUnpacked = function(self, x, y) 109 | self.x = x 110 | self.y = y 111 | end, 112 | 113 | GetPos = function(self) 114 | return Vector2(self.x, self.y) 115 | end 116 | } 117 | 118 | metaTable_Vector2.__index = metaTable_Vector2 119 | 120 | function isvector2(v) 121 | return getmetatable(v) == metaTable_Vector2 122 | end 123 | 124 | function Vector2(x, y) 125 | local Vector2 = { 126 | x = x, 127 | y = y 128 | } 129 | 130 | return setmetatable(Vector2, metaTable_Vector2) 131 | end 132 | 133 | function tween.Lerp(from, to, t) 134 | return (1 - t) * from + t * to 135 | end 136 | 137 | local Lerp = tween.Lerp 138 | 139 | local function CalcAng(from, to) 140 | local diff = math_fmod(to - from, 360) 141 | 142 | return math_fmod(2 * diff, 360) - diff 143 | end 144 | 145 | local function LerpDeg(from, to, t) 146 | return from + CalcAng(from, to) * t 147 | end 148 | 149 | function tween.LerpAngle(from, to, t) 150 | return Angle( 151 | LerpDeg(from.p, to.p, t), 152 | LerpDeg(from.y, to.y, t), 153 | LerpDeg(from.r, to.r, t) 154 | ) 155 | end 156 | 157 | local LerpAngle = tween.LerpAngle 158 | 159 | local function LerpVector2Unpacked(vector2, from, to, t) 160 | local lerped_vector2 = Lerp(from, to, t) 161 | 162 | vector2:SetUnpacked(lerped_vector2.x, lerped_vector2.y) 163 | end 164 | 165 | local function LerpVectorUnpacked(vector, from, to, t) 166 | local lerped_vector = Lerp(from, to, t) 167 | 168 | vector:SetUnpacked(lerped_vector.x, lerped_vector.y, lerped_vector.z) 169 | end 170 | 171 | local function LerpColor(from, to, t) 172 | return Color( 173 | Lerp(from.r, to.r, t), 174 | Lerp(from.g, to.g, t), 175 | Lerp(from.b, to.b, t), 176 | Lerp(from.a, to.a, t) 177 | ) 178 | end 179 | 180 | local function LerpColorUnpacked(color, from, to, t) 181 | color:SetUnpacked( 182 | Lerp(from.r, to.r, t), 183 | Lerp(from.g, to.g, t), 184 | Lerp(from.b, to.b, t), 185 | Lerp(from.a, to.a, t) 186 | ) 187 | end 188 | 189 | local function LerpAngleUnpacked(angle, from, to, t) 190 | angle:SetUnpacked( 191 | LerpDeg(from.p, to.p, t), 192 | LerpDeg(from.y, to.y, t), 193 | LerpDeg(from.r, to.r, t) 194 | ) 195 | end 196 | 197 | local function BinomialCoefficient(n, k) 198 | local result = 1 199 | 200 | for i = 1, k do 201 | result = result * (n - i + 1) / i 202 | end 203 | 204 | return result 205 | end 206 | 207 | function tween.BSpline(points, t) 208 | local n = #points 209 | local result = Vector_0 210 | 211 | for i = 1, n do 212 | local weight = BinomialCoefficient(n - 1, i - 1) * math_pow(1 - t, n - i) * math_pow(t, i - 1) 213 | 214 | result = result + weight * points[i] 215 | end 216 | 217 | return result 218 | end 219 | 220 | local BSpline = tween.BSpline 221 | 222 | local all_tweens = {} 223 | local running_tweens = {} 224 | local paused_tweens = {} 225 | local stopped_tweens = {} 226 | 227 | local type_to_function = { 228 | ["number"] = Lerp, 229 | ["vector2"] = Lerp, 230 | ["vector"] = Lerp, 231 | ["color"] = LerpColor, 232 | ["angle"] = LerpAngle 233 | } 234 | 235 | local type_to_function_unpacked = { 236 | ["number"] = Lerp, 237 | ["vector2"] = LerpVector2Unpacked, 238 | ["vector"] = LerpVectorUnpacked, 239 | ["color"] = LerpColorUnpacked, 240 | ["angle"] = LerpAngleUnpacked 241 | } 242 | 243 | local function tween_type(object) 244 | return isvector2(object) and "vector2" 245 | or IsColor(object) and "color" 246 | or type(object):lower() 247 | end 248 | 249 | local metaTable_Tween = { 250 | __newindex = function(self, key, value) 251 | rawset(self, key, value) 252 | end, 253 | 254 | Start = function(self) 255 | self.running = true 256 | self.start_time = SysTime() 257 | self.end_time = self.start_time + self.duration 258 | self.time_left = self.duration 259 | self.tween_type = tween_type(self.from) 260 | self.lerp_type = type_to_function[self.tween_type] 261 | 262 | all_tweens[self] = true 263 | running_tweens[self] = true 264 | end, 265 | 266 | SetPermanent = function(self, bool) 267 | self.permanent = bool 268 | end, 269 | 270 | SetFrom = function(self, from) 271 | self.from = from 272 | end, 273 | 274 | SetTo = function(self, to) 275 | self.to = to 276 | end, 277 | 278 | SetWaypoints = function(self, from, to) 279 | self.from = from 280 | self.to = to 281 | end, 282 | 283 | SetDuration = function(self, duration) 284 | self.duration = duration 285 | end, 286 | 287 | SetEaseType = function(self, ease_type) 288 | self.ease_type = ease_type 289 | end, 290 | 291 | Restart = function(self) 292 | if !all_tweens[self] then 293 | self:Start() 294 | 295 | return 296 | end 297 | 298 | self.running = true 299 | self.start_time = SysTime() 300 | self.end_time = self.start_time + self.duration 301 | self.time_left = self.duration 302 | 303 | if !running_tweens[self] then 304 | running_tweens[self] = true 305 | end 306 | 307 | if paused_tweens[self] then 308 | paused_tweens[self] = nil 309 | elseif stopped_tweens[self] then 310 | stopped_tweens[self] = nil 311 | end 312 | end, 313 | 314 | Pause = function(self) 315 | if stopped_tweens[self] then return end 316 | 317 | self.running = false 318 | 319 | if running_tweens[self] then 320 | running_tweens[self] = nil 321 | paused_tweens[self] = true 322 | end 323 | end, 324 | 325 | Resume = function(self) 326 | if stopped_tweens[self] then 327 | self:Restart() 328 | 329 | return 330 | end 331 | 332 | self.start_time = SysTime() - (self.duration - self.time_left) 333 | self.end_time = self.start_time + self.duration 334 | self.running = true 335 | 336 | if paused_tweens[self] then 337 | paused_tweens[self] = nil 338 | running_tweens[self] = true 339 | end 340 | end, 341 | 342 | Stop = function(self) 343 | self.running = false 344 | 345 | if running_tweens[self] then 346 | running_tweens[self] = nil 347 | elseif paused_tweens[self] then 348 | paused_tweens[self] = nil 349 | end 350 | 351 | stopped_tweens[self] = true 352 | end, 353 | 354 | Update = function(self) 355 | if self.running then 356 | local time = SysTime() 357 | self.time_left = self.end_time - time 358 | 359 | if time >= self.end_time then 360 | self.running = false 361 | self.value = self.to 362 | 363 | if !self.permanent then 364 | all_tweens[self] = nil 365 | running_tweens[self] = nil 366 | end 367 | 368 | if self.callback != nil then 369 | self.callback(self) 370 | end 371 | 372 | return 373 | end 374 | 375 | local alpha = (time - self.start_time) / self.duration 376 | 377 | self.value = self.lerp_type(self.from, self.to, self.ease_type(alpha)) 378 | 379 | local OnUpdate = self.OnUpdate 380 | 381 | if OnUpdate and isfunction(OnUpdate) then 382 | self:OnUpdate() 383 | end 384 | end 385 | end, 386 | 387 | TimeLeft = function(self) 388 | return self.time_left 389 | end, 390 | 391 | GetValue = function(self) 392 | return self.value 393 | end, 394 | 395 | Destroy = function(self) 396 | all_tweens[self] = nil 397 | 398 | if running_tweens[self] then 399 | running_tweens[self] = nil 400 | elseif paused_tweens[self] then 401 | paused_tweens[self] = nil 402 | elseif stopped_tweens[self] then 403 | stopped_tweens[self] = nil 404 | end 405 | end, 406 | 407 | SetCallback = function(self, callback) 408 | self.callback = callback 409 | end 410 | } 411 | 412 | metaTable_Tween.__index = metaTable_Tween 413 | 414 | function Tween(from, to, duration, ease_type, callback) 415 | local Tween = { 416 | from = from, 417 | to = to, 418 | duration = duration, 419 | ease_type = ease_type, 420 | callback = callback, 421 | value = from, 422 | time_left = duration, 423 | permanent = false, 424 | running = false 425 | } 426 | 427 | return setmetatable(Tween, metaTable_Tween) 428 | end 429 | 430 | local metaTable_TweenUnpacked = { 431 | Start = function(self) 432 | self.running = true 433 | self.start_time = SysTime() 434 | self.end_time = self.start_time + self.duration 435 | self.time_left = self.duration 436 | self.tween_type = tween_type(self.base_object) 437 | self.lerp_type_unpacked = type_to_function_unpacked[self.tween_type] 438 | 439 | all_tweens[self] = true 440 | running_tweens[self] = true 441 | end, 442 | 443 | Update = function(self) 444 | if self.running then 445 | local to = self.to 446 | local time = SysTime() 447 | self.time_left = self.end_time - time 448 | 449 | if time >= self.end_time then 450 | self.running = false 451 | self.value = to 452 | self.base_object = to 453 | 454 | if !self.permanent then 455 | all_tweens[self] = nil 456 | running_tweens[self] = nil 457 | end 458 | 459 | if self.callback != nil then 460 | self.callback() 461 | end 462 | 463 | return 464 | end 465 | 466 | local alpha = (time - self.start_time) / self.duration 467 | 468 | if self.tween_type == "number" then 469 | self.value = Lerp(self.from, to, self.ease_type(alpha)) 470 | else 471 | local base_object = self.base_object 472 | self.lerp_type_unpacked(base_object, self.from, to, self.ease_type(alpha)) 473 | self.value = base_object 474 | end 475 | 476 | local OnUpdate = self.OnUpdate 477 | 478 | if OnUpdate and isfunction(OnUpdate) then 479 | self:OnUpdate() 480 | end 481 | end 482 | end 483 | } 484 | 485 | table_Inherit(metaTable_TweenUnpacked, metaTable_Tween) 486 | 487 | metaTable_TweenUnpacked.__index = metaTable_TweenUnpacked 488 | 489 | function TweenUnpacked(base_object, from, to, duration, ease_type, callback) 490 | local Tween = { 491 | base_object = base_object, 492 | from = from, 493 | to = to, 494 | duration = duration, 495 | ease_type = ease_type, 496 | callback = callback, 497 | value = from, 498 | time_left = duration, 499 | permanent = false, 500 | running = false 501 | } 502 | 503 | return setmetatable(Tween, metaTable_TweenUnpacked) 504 | end 505 | 506 | local metaTable_BezierTween = { 507 | Start = function(self) 508 | self.running = true 509 | self.start_time = SysTime() 510 | self.end_time = self.start_time + self.duration 511 | self.time_left = self.duration 512 | self.value = self.points[1] 513 | 514 | all_tweens[self] = true 515 | running_tweens[self] = true 516 | end, 517 | 518 | Update = function(self) 519 | if self.running then 520 | local points = self.points 521 | local time = SysTime() 522 | self.time_left = self.end_time - time 523 | 524 | if time >= self.end_time then 525 | self.running = false 526 | self.value = points[#points] 527 | 528 | if !self.permanent then 529 | all_tweens[self] = nil 530 | running_tweens[self] = nil 531 | end 532 | 533 | if self.callback != nil then 534 | self.callback(self) 535 | end 536 | 537 | return 538 | end 539 | 540 | local alpha = (time - self.start_time) / self.duration 541 | 542 | self.value = BSpline(points, self.ease_type(alpha)) 543 | 544 | local OnUpdate = self.OnUpdate 545 | 546 | if OnUpdate and isfunction(OnUpdate) then 547 | self:OnUpdate() 548 | end 549 | end 550 | end, 551 | } 552 | 553 | table_Inherit(metaTable_BezierTween, metaTable_Tween) 554 | 555 | metaTable_BezierTween.__index = metaTable_BezierTween 556 | 557 | function BezierTween(points, duration, ease_type, callback) 558 | local Tween = { 559 | points = points, 560 | duration = duration, 561 | ease_type = ease_type, 562 | callback = callback, 563 | value = points[1], 564 | time_left = duration, 565 | permanent = false, 566 | running = false, 567 | } 568 | 569 | return setmetatable(Tween, metaTable_BezierTween) 570 | end 571 | 572 | hook.Add("Think", "process_tweens", function() 573 | if table.IsEmpty(running_tweens) then return end 574 | 575 | for tween in next, running_tweens do 576 | if tween == nil then continue end 577 | 578 | tween:Update() 579 | end 580 | end) --------------------------------------------------------------------------------