Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Why do these parts being created move slower over time in a loop?

Asked by
Reivani 11
5 years ago

Hello, I've posted about this bug a few times before. I've been trying to make a script that creates square blocks in random positions spread around following the camera. This is my code, the area that I've changed to a comment was the fix someone gave for the code, which was to check if the brick still existed, and if not break the loop.

local debris = game:GetService("Debris")

local cam = workspace.CurrentCamera
local rand = math.random
local num = 25

while true do
    for i = 0, 10 do
        local brick = Instance.new("Part")
        brick.Anchored = true
        brick.CanCollide = false
        brick.Size = Vector3.new(1, 1, 1)
        brick.Parent = workspace
        brick.CFrame = CFrame.new(cam.CFrame.Position + Vector3.new(rand(-num, num), rand(-num, num), rand(-num, num)))
        debris:AddItem(brick, 0.75)

        local function moveUp()
            while true do
                brick.CFrame = brick.CFrame * CFrame.new(0, 0.1, 0)
                --[[ if not brick.Parent then
                    break
                    end ]]-- 
                wait()
            end
        end
        spawn(moveUp)

    end
    wait()
end

Originally I thought the user in the last post that I linked to solved the issue, but now I've realized that the more I increase the debris AddItem duration, the less smoothly the bricks move again, putting me back to square one.

If anyone could tackle this bug, it would mean a lot. If I've been unclear in any way, please let me know. Thanks.

0
try changing while true do of line 18 to game:GetService("RunService").RenderStepped:Connect(function() and remove the wait, I think it will go faster yHasteeD 1819 — 5y

1 answer

Log in to vote
0
Answered by 5 years ago

First off, I have to congratulate you: your code is honestly as good as it's possible to get as a beginner, and your question was informative and very well worded. That said, let's get into the problem.

Your issue here is that, basically, while loops suck, and are your issue. The correct way to handle repeated calls/loops in ROBLOX is with the game's "RunService". With it, you can essentially schedule functions to run at a constant-ish interval - usually 60 times per second. Using this service is almost ALWAYS better than using while - wait loops for game logic because it is more consistent and can provide MUCH better performance and clarity. Also, you can't have your game crash because of an infinite loop with no "wait()" :P.

First, some background on how it works. Essentially what you're doing when you use RunService is you're giving the game engine some code that you want it to run without your input over and over. It does this by "linking" the code you want to run in the form of a function to a so-called "event". That's what ":Connect" does in the code below. Every time the event is fired - 60 times per second in this case - your linked code is run! Easy! Events are SUPER powerful, and I highly suggest reading up on them.

So, let's replace your main while loop with RunService.

local debris = game:GetService("Debris")
local runService = game:GetService("RunService")

local cam = workspace.CurrentCamera
local rand = math.random
local num = 25

runService.Stepped:Connect(function() --This function/code will run at 60 times/second, instead of about 30 with "wait()"
    for i = 0, 5 do --Because of the better performance, create less parts per iteration
        local brick = Instance.new("Part")
        brick.Anchored = true
        brick.CanCollide = false
        brick.Size = Vector3.new(1, 1, 1)
        brick.CFrame = CFrame.new(cam.CFrame.Position + Vector3.new(rand(-num, num), rand(-num, num), rand(-num, num)))
        brick.Parent = workspace --Only set a part's parent to workspace AFTER all properties have been set for best performance.
        debris:AddItem(brick, 0.75)
    end
    --Notice we got rid of the wait(). It's not needed anymore!
end)

Notice that I omitted the code that animates the bricks above. Of course, we could just do a similar thing to the animation loop as we just did - replacing the while loop with an event connection - however, ROBLOX provides a much better way to do things like this - TweenService. (This is worth it, trust me!). TweenService basically handles animation in-game for you in an efficient and easy-to-understand way. Here's the code:

local tweenService = game:GetService("TweenService")
local cam = workspace.CurrentCamera
local rand = math.random
local num = 25
game:GetService("RunService").Stepped:Connect(function()
    for i = 0, 5 do
        local brick = Instance.new("Part")
        brick.Anchored = true
        brick.CanCollide = false
        brick.Size = Vector3.new(1, 1, 1)
        brick.CFrame = CFrame.new(cam.CFrame.Position + Vector3.new(rand(-num, num), rand(-num, num), rand(-num, num)))
        brick.Parent = workspace

        local tweenInfo = TweenInfo.new(.75,
            Enum.EasingStyle.Linear)
        local tween = tweenService:Create(brick, tweenInfo, {CFrame = brick.CFrame + Vector3.new(0,10,0)})
        tween.Completed:Connect(function() brick:Destroy() end)
        tween:Play()
    end
end)

Ok, let's go through what's going on here. The first new element is the call to TweenInfo.new(...), which gives us an object that can pass settings into the actual tween. In our case, we have set the duration of the tween to be .75 sec and the style of tween to be linear. Play around with these settings, you can find a full list on the wiki here. Next, we actually create the tween that will handle the animation for us with "tweenService:Create()". It takes the object to animate (The brick), the tweenInfo object we created earlier, and an object that describes a final property - In this case, we want our brick's final CFrame to be its current one offset vertically by 10 units. Then, we link a function that destroys the brick to the "Completed" event of the tween. This will, as you might expect, destroy the brick after the tween is finished animating. All that's left to do is start the animation, with "tween:Play()"! This, in the end, gets you buttery smooth animation with minimal (~5%) performance penalty!

Happy Coding!

0
This was an incredibly in-depth response to the problem, thank you! I think I've learnt a lot from this. The code seems to run smoothly now. Reivani 11 — 5y
Ad

Answer this question