[Tween Service] Breaking on laggy low-end devices

:scroll: The Basics

  • I’ve made a fully OOP tycoon system, in which I’ve tried to optimise as best as I can. There’s a function in which when an item has been bought, it’s passed over the the client to be animated using Tween Service and CFraming on the descendant base parts.

:rotating_light: The Issue

  • Essentially, the issue I’m currently faced with is that, it works flawlessly on pc, and devices that have a stable connection however, as soon as an unstable connection is involved within the system, it’s breaking the Tween half-way, leading to floating half-transparent parts, instead of it fully playing the tween, or not even showing the item at all.

    Screenshot from laggy device showcasing the issue.

:thinking: What I’ve Tried

  • I first thought it could have been to do with the Run Service render step wait, so I changed this out to just using task.wait(0.05); this didn’t help.
  • I then tried to make it animate all parts at once in “batches”, and remove the wait, as I thought that the waiting between tweens could have been the issue; this didn’t help, if at all made it worse.
  • I did try to wrap the whole of the remote call in a coroutine, however, the same issue still arose.

Note: I cannot make it tween all the parts together as on low-end devices, running over 35+ tweens at once causes a lot of client-sided lag.

:technologist: The Code

Net:On("ItemAnimation", function(model, descCount)
    local descCountTemp = 0

    local connection = model.DescendantAdded:Connect(function(part)
        if part:IsA("BasePart") or part:IsA("UnionOperation") then
            descCountTemp += 1
        end
    end)

    repeat
        task.wait(0.05)
    until descCountTemp == descCount

    local originalTransparency = {}
    local originalCFrames = {}
    local orignalCanCollide = {}

    for _, v in model:GetDescendants() do
        if v:IsA("BasePart") or v:IsA("UnionOperation") then
            originalTransparency[v] = v.Transparency
            originalCFrames[v] = v.CFrame
            orignalCanCollide[v] = v.CanCollide
            v.Transparency = 1
            v.CanCollide = false
        end
    end

    for _, v in model:GetDescendants() do
        if v:IsA("BasePart") or v:IsA("MeshPart") or v:IsA("UnionOperation") then
            local positionOffset = Vector3.new(Random.new():NextNumber(-4, 4), Random.new():NextNumber(1, 4), Random.new():NextNumber(-4, 4))
            local rotationOffset = CFrame.Angles(Random.new():NextNumber(-0.5, 0.5), Random.new():NextNumber(-0.5, 0.5), Random.new():NextNumber(-0.5, 0.5))
            
            v.CFrame = v.CFrame * CFrame.new(positionOffset) * rotationOffset

            TweenService:Create(v, TweenInfo.new(1, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out), {CFrame = originalCFrames[v]}):Play()
            TweenService:Create(v, TweenInfo.new(0.25, Enum.EasingStyle.Quart, Enum.EasingDirection.Out), {Transparency = originalTransparency[v]}):Play()
            
            RunService.RenderStepped:Wait()
        end
    end

    task.wait(0.8)

    for _, v in model:GetDescendants() do
        if v:IsA("BasePart") or v:IsA("MeshPart") or v:IsA("UnionOperation") then
            v.CanCollide = orignalCanCollide[v]
        end
    end

    connection:Disconnect()
end)

Any help or directions are appreciated, thanks!

In the last loop where you change the value of CanCollide why don’t you set all the values that has been changed to the value that they should be? That’ll ensure all properties are correct and if for any reason the tween didn’t continue, this will force it to reach the end.

I could do however, it could end up leading to lag. I’ll give it a shot and see how it goes.

It wouldn’t really lead to lag as the tween won’t stop/stutter until the user is already lagging. Good luck.

Just tried, and the issue is still apparent.