Last active
November 2, 2022 18:42
-
-
Save howmanysmall/70a99ed4baa4d4d6db32dea2e8944407 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local ReplicatedStorage = game:GetService("ReplicatedStorage") | |
| local HttpService = game:GetService("HttpService") | |
| local RunService = game:GetService("RunService") | |
| local Janitor = require(ReplicatedStorage.Knit.Util.Janitor) | |
| local Roact = require(ReplicatedStorage.Shared.Vendor.Roact) | |
| local RoactHooked = require(ReplicatedStorage.Shared.Vendor.RoactHooked) | |
| local UDim2 = require(ReplicatedStorage.Shared.Utility.DataTypes.UDim2) | |
| local FUZZ = 0.2 | |
| local FORCE = 30 | |
| local FORCE_FUZZ = 20 | |
| local DRAG = 0.95 | |
| local GRAVITY = 0.2 | |
| local ROTATE_SPEED = 1 | |
| export type IConfettiProps = { | |
| FireParticles: RBXScriptSignal, | |
| } | |
| local RandomLib = Random.new(os.clock() % 1 * 1E7) | |
| local NextInteger = RandomLib.NextInteger | |
| local NextNumber = RandomLib.NextNumber | |
| local function Confetti(props: IConfettiProps) | |
| local absoluteSize, setAbsoluteSize = RoactHooked.UseBinding(Vector2.zero) | |
| local state, setState = RoactHooked.UseSetState({}) | |
| local forceUpdate = RoactHooked.UseForceUpdate() | |
| local ref = RoactHooked.UseRef() | |
| local onChange = RoactHooked.UseCallback(function(rbx: Frame) | |
| setAbsoluteSize(rbx.AbsoluteSize) | |
| end, {}) | |
| local fireConfetti = RoactHooked.UseCallback(function(amount: number, origin: Vector2, direction: Vector2) | |
| local newParticleSet = table.clone(state) | |
| for _ = 1, amount do | |
| local velocity = direction.Unit | |
| velocity += Vector2.new(NextNumber(RandomLib, -FUZZ, FUZZ), NextNumber(RandomLib, -FUZZ, FUZZ)) | |
| velocity = velocity.Unit*(FORCE + NextNumber(RandomLib, -FORCE_FUZZ, FORCE_FUZZ)) | |
| local confettiLength = NextNumber(RandomLib, 10, 20) | |
| local confettiWidth = confettiLength*NextNumber(RandomLib, 0.4, 0.6) | |
| newParticleSet[{ | |
| BackgroundColor3 = Color3.fromHSV(NextNumber(RandomLib), 0.5, 1), | |
| Guid = HttpService:GenerateGUID(false), | |
| Size = UDim2.fromOffset(confettiLength, confettiWidth), | |
| X = origin.X, | |
| Y = origin.Y, | |
| Rotation = NextInteger(RandomLib, 0, 360), | |
| Lifetime = 5 + NextNumber(RandomLib, 0, 2), | |
| VelocityX = velocity.X, | |
| VelocityY = velocity.Y, | |
| }] = true | |
| end | |
| setState(newParticleSet) | |
| end, {state}) | |
| local onFire = RoactHooked.UseCallback(function(amount: number) | |
| local localAbsoluteSize = absoluteSize:getValue() | |
| fireConfetti(amount, localAbsoluteSize*Vector2.yAxis, Vector2.new(1, -1)) | |
| fireConfetti(amount, localAbsoluteSize, Vector2.new(-1, -1)) | |
| end, {fireConfetti}) | |
| local onHeartbeat = RoactHooked.UseCallback(function(deltaTime: number) | |
| local newParticleSet = table.clone(state) | |
| for particle in newParticleSet do | |
| local lifetime = particle.Lifetime | |
| local newLifetime = lifetime - deltaTime | |
| if newLifetime <= 0 then | |
| newParticleSet[particle] = Roact.None | |
| continue | |
| else | |
| particle.Lifetime = newLifetime | |
| end | |
| local velocityX = particle.VelocityX | |
| local velocityY = particle.VelocityY | |
| particle.X += velocityX | |
| particle.Y += velocityY | |
| particle.VelocityX = velocityX*DRAG | |
| particle.VelocityY = velocityY*DRAG + GRAVITY | |
| particle.Rotation += ROTATE_SPEED | |
| end | |
| setState(newParticleSet) | |
| forceUpdate() | |
| end, {state}) | |
| RoactHooked.UseEffect(function() | |
| local janitor = Janitor.new() | |
| local fireParticles = props.FireParticles | |
| if fireParticles then | |
| janitor:Add(fireParticles:Connect(onFire), "Disconnect") | |
| end | |
| janitor:Add(RunService.Heartbeat:Connect(onHeartbeat), "Disconnect") | |
| return function() | |
| janitor:Destroy() | |
| end | |
| end, {}) | |
| RoactHooked.UseEffect(function() | |
| local rbx = ref:getValue() | |
| if rbx then | |
| setAbsoluteSize(rbx.AbsoluteSize) | |
| end | |
| end, {}) | |
| local children = {} | |
| for particle in state do | |
| children[particle.Guid] = Roact.createElement("Frame", { | |
| BackgroundColor3 = particle.BackgroundColor3, | |
| BackgroundTransparency = 1 - math.clamp(particle.Lifetime, 0, 1), | |
| BorderSizePixel = 0, | |
| Position = UDim2.fromOffset(particle.X, particle.Y), | |
| Rotation = particle.Rotation, | |
| Size = particle.Size, | |
| }) | |
| end | |
| return Roact.createElement("Frame", { | |
| BackgroundTransparency = 1, | |
| ClipsDescendants = true, | |
| Size = UDim2.oneScale, | |
| ZIndex = -100, | |
| [Roact.Change.AbsoluteSize] = onChange, | |
| [Roact.Ref] = ref, | |
| }, children) | |
| end | |
| return RoactHooked.HookPure(Confetti, {Name = "Confetti"}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Compiled with roblox-ts v1.3.3 | |
| local TS = require(game:GetService("ReplicatedStorage"):WaitForChild("rbxts_include"):WaitForChild("RuntimeLib")) | |
| local HttpService = game:GetService("HttpService") | |
| local RunService = game:GetService("RunService") | |
| local Hooks = TS.import(script, TS.getModule(script, "@rbxts", "roact-hooks").src) | |
| local _roact = TS.import(script, TS.getModule(script, "@rbxts", "roact").src) | |
| local Roact = _roact | |
| local None = _roact.None | |
| local Janitor = TS.import(script, TS.getModule(script, "@rbxts", "janitor").src).Janitor | |
| local useForceUpdate = TS.import(script, script.Parent.Parent.Parent, "roact-hooks", "useForceUpdate").default | |
| local useSetState = TS.import(script, script.Parent.Parent.Parent, "roact-hooks", "useSetState").default | |
| local assign = TS.import(script, script.Parent.Parent.Parent, "roact-hooks", "utility", "roact-assign") | |
| local oneScale = TS.import(script, game:GetService("ReplicatedStorage"), "TS", "modules", "utility", "udim2").oneScale | |
| local fromEqual = TS.import(script, game:GetService("ReplicatedStorage"), "TS", "modules", "utility", "vector2").fromEqual | |
| local FUZZ = 0.2 | |
| local FORCE = 30 | |
| local FORCE_FUZZ = 20 | |
| local DRAG = 0.95 | |
| local GRAVITY = 0.2 | |
| local ROTATE_SPEED = 1 | |
| local randomLib = Random.new((os.clock() % 1) * 1e7) | |
| local Component = function(props, hooks) | |
| local absoluteSize, setAbsoluteSize = hooks.useBinding(Vector2.zero) | |
| local state, setState = useSetState(hooks, {}) | |
| local forceUpdate = useForceUpdate(hooks) | |
| local ref = hooks.useValue(Roact.createRef()).value | |
| local onChange = hooks.useCallback(function(rbx) | |
| return setAbsoluteSize(rbx.AbsoluteSize) | |
| end, {}) | |
| local fireConfetti = hooks.useCallback(function(amount, origin, direction) | |
| local newParticleSet = table.clone(state) | |
| do | |
| local index = 0 | |
| local _shouldIncrement = false | |
| while true do | |
| if _shouldIncrement then | |
| index += 1 | |
| else | |
| _shouldIncrement = true | |
| end | |
| if not (index < amount) then | |
| break | |
| end | |
| local velocity = direction.Unit | |
| local _velocity = velocity | |
| local _vector2 = Vector2.new(randomLib:NextNumber(-FUZZ, FUZZ), randomLib:NextNumber(-FUZZ, FUZZ)) | |
| velocity = _velocity + _vector2 | |
| local _unit = velocity.Unit | |
| local _arg0 = FORCE + randomLib:NextNumber(-FORCE_FUZZ, FORCE_FUZZ) | |
| velocity = _unit * _arg0 | |
| local confettiLength = randomLib:NextNumber(10, 20) | |
| local confettiWidth = confettiLength * randomLib:NextNumber(0.4, 0.6) | |
| local _arg0_1 = { | |
| BackgroundColor3 = Color3.fromHSV(randomLib:NextNumber(), 0.5, 1), | |
| Size = UDim2.fromOffset(confettiLength, confettiWidth), | |
| Guid = HttpService:GenerateGUID(false), | |
| X = origin.X, | |
| Y = origin.Y, | |
| Rotation = randomLib:NextInteger(0, 360), | |
| Lifetime = 5 + randomLib:NextNumber(0, 2), | |
| VelocityX = velocity.X, | |
| VelocityY = velocity.Y, | |
| } | |
| newParticleSet[_arg0_1] = true | |
| end | |
| end | |
| setState(newParticleSet) | |
| end, { state }) | |
| local onFire = hooks.useCallback(function(amount) | |
| local localAbsoluteSize = absoluteSize:getValue() | |
| local _yAxis = Vector2.yAxis | |
| fireConfetti(amount, localAbsoluteSize * _yAxis, Vector2.new(1, -1)) | |
| fireConfetti(amount, localAbsoluteSize, fromEqual(-1)) | |
| end, { fireConfetti }) | |
| local onHeartbeat = hooks.useCallback(function(deltaTime) | |
| local newParticleSet = table.clone(state) | |
| local deleteParticles = {} | |
| for particle in pairs(newParticleSet) do | |
| local lifetime = particle.Lifetime | |
| local newLifetime = lifetime - deltaTime | |
| if newLifetime <= 0 then | |
| newParticleSet[particle] = nil | |
| deleteParticles[particle] = None | |
| continue | |
| else | |
| particle.Lifetime = newLifetime | |
| end | |
| local velocityX = particle.VelocityX | |
| local velocityY = particle.VelocityY | |
| particle.X += velocityX | |
| particle.Y += velocityY | |
| particle.VelocityX = velocityX * DRAG | |
| particle.VelocityY = velocityY * DRAG + GRAVITY | |
| particle.Rotation += ROTATE_SPEED | |
| end | |
| setState(function(particleSet) | |
| return assign(assign(particleSet, newParticleSet), deleteParticles) | |
| end) | |
| forceUpdate() | |
| end, { state }) | |
| hooks.useEffect(function() | |
| local janitor = Janitor.new() | |
| local fireParticles = props.FireParticles | |
| if fireParticles then | |
| janitor:Add(fireParticles:Connect(onFire), "Disconnect") | |
| end | |
| janitor:Add(RunService.Heartbeat:Connect(onHeartbeat), "Disconnect") | |
| return function() | |
| return janitor:Destroy() | |
| end | |
| end, {}) | |
| hooks.useEffect(function() | |
| local frame = ref:getValue() | |
| if frame then | |
| onChange(frame) | |
| end | |
| end, {}) | |
| local children = {} | |
| for particle in pairs(state) do | |
| local _arg0 = Roact.createFragment({ | |
| [particle.Guid] = Roact.createElement("Frame", { | |
| BackgroundColor3 = particle.BackgroundColor3, | |
| BackgroundTransparency = 1 - math.clamp(particle.Lifetime, 0, 1), | |
| BorderSizePixel = 0, | |
| Position = UDim2.fromOffset(particle.X, particle.Y), | |
| Rotation = particle.Rotation, | |
| Size = particle.Size, | |
| }), | |
| }) | |
| table.insert(children, _arg0) | |
| end | |
| local _attributes = { | |
| BackgroundTransparency = 1, | |
| [Roact.Change.AbsoluteSize] = onChange, | |
| ClipsDescendants = true, | |
| [Roact.Ref] = ref, | |
| Size = oneScale, | |
| ZIndex = -100, | |
| } | |
| local _children = {} | |
| local _length = #_children | |
| for _k, _v in ipairs(children) do | |
| _children[_length + _k] = _v | |
| end | |
| return Roact.createElement("Frame", _attributes, _children) | |
| end | |
| local Confetti = Hooks.new(Roact)(Component, { | |
| componentType = "PureComponent", | |
| name = "Confetti", | |
| }) | |
| local default = Confetti | |
| return { | |
| Confetti = Confetti, | |
| default = default, | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment