Script rate is way too much

Hello.
I am making a simple bullet controller, where the bullet moves by a certain amount with delays.
I am trying to utilize parallel luau, but I’ve encountered some problems, the script rate is extremely high(>100) even though im using task.wait(1) inside the loops.
Heres the script:

repeat
		local TargetCFrame = Bullet.Object.CFrame*CFrame.new(-Bullet.Speed*10,0,0)
		task.synchronize()
		game.TweenService:Create(Bullet.Object,TweenInfo.new(1,Enum.EasingStyle.Linear),{CFrame = TargetCFrame}):Play()
		task.desynchronize()
		task.wait(1)
	until (Bullet.Object.Position-Vector3.zero).Magnitude > 100

I am very new to this parallel luau stuff, so do tell me if im doing something wrong. Help would be much appreciated.

1 Like

It’s due to you using parralell luau. Parralell luau ignores task.wait() you could say. It does not run with the normal thread, but rather with the thread, so unless you have a task.wait() inside the thread, its gonna just run really fast.

Instead of using task.synchronize() and task.desynchronize(), you can try using task.spawn() to create a new task for the bullet movement.

repeat
    local TargetCFrame = Bullet.Object.CFrame * CFrame.new(-Bullet.Speed * 10, 0, 0)
    task.spawn(function()
        game.TweenService:Create(Bullet.Object, TweenInfo.new(1, Enum.EasingStyle.Linear), { CFrame = TargetCFrame }):Play()
    end)
    task.wait(1)
until (Bullet.Object.Position - Vector3.zero).Magnitude > 100

By using task.spawn(), the bullet movement will be executed in a separate task, which can help improve the script rate. The task.wait(1) will still introduce a delay between each bullet movement.

1 Like

Or you do could do this too^ (but I would use task.defer)

3 Likes

This code is in a ConnectParallel connection, so it throws an error saying its unsafe.
Should I just connect it normally?

2 Likes

I tried using task.defer but it just made the rate higher…

1 Like

task.defer uses a function on the next heartbeat, so thats the reason for sure. Don’t use any task function with the exeption of task.wait(), or just don’t use parallel. If you want a low rate, serial (aka the default) is 60/s max. Parallel does have its upsides though, so I recommend use it, when possible, as it really does not hurt the script as it’s running alongside.

2 Likes

You could also try:

local RunService = game:GetService("RunService")

local function moveBullet()
    local bullet = Bullet.Object
    local targetCFrame = bullet.CFrame * CFrame.new(-Bullet.Speed * 10, 0, 0)
    game.TweenService:Create(bullet, TweenInfo.new(1, Enum.EasingStyle.Linear), { CFrame = targetCFrame }):Play()
end

local function checkDistance()
    local distance = (Bullet.Object.Position - Vector3.zero).Magnitude
    return distance > 100
end

RunService.Heartbeat:Connect(function()
    if checkDistance() then
        moveBullet()
    end
end)

Use the RunService.Heartbeat event to continuously check the distance and move the bullet if necessary. The moveBullet() function handles the bullet movement using TweenService, and the checkDistance() function determines whether the bullet should continue moving.

1 Like

Consider using the microprofiler instead to measure performance.

Script activity is a quick indicator, but doesnt tell the whole story and had some bugs in the past.

Script rate however doesnt really tell much if it uses a renderstep loop it will be really high but the performance cost may thr low such as some camera CFraming.

3 Likes

I’m unsure why but this surpasses the 60/s rate limit by a lot even though im pretty sure i didnt use any parallel stuff.
Script performance is 49% or so, very high compared to the parallel one.

1 Like

Because a loop without wait time run as fast as possible, generaly at (0.001) to (0.0001) something like that, and most of the time it make the game crash.

Every Repeat Until and While Do loops must have a task.wait() to limit the rate at your FPS count, the minimum being 30/s (0.03)


Any script activity shouldn’t be above 3%, and the rate of a script doesn’t matter as long as your script is optimized… if your script activity really is at 49% then there’s a huge performance issue.


If the overall code is the same then the performances doesn’t change in reality, you’re just moving a part of the unoptimized code to an another thread so it isn’t shown as a part of the script.


Also, i don’t understand why do you want to run a Tween into a new thread while it isn’t even yielding the script at all, it is not needed.

1 Like

Isn’t the loop a connection to heartbeat? In that case shouldnt it be limited to 1/60?

I didn’t realize this until you said so, thanks! :sweat_smile:

Surprisingly the script performance was 7% or so on the script on the original post, i have no idea why.

1 Like

From what i saw a lot of times on the forum, it is not, that’s why you need to use task.wait so it connect the loop to heartbeat, same as runservice.Heartbeat

7% is still too much ^^
This come only from this single loop ?

Doing something like this should reduce it

local TweenService = game:GetService("TweenService")

local Info = TweenInfo.new(1, Enum.EasingStyle.Linear)
local Object = Bullet.Object
local TargetCFrame = nil

repeat
	TargetCFrame = Object.CFrame * CFrame.new(-Bullet.Speed*10, 0, 0)
	TweenService:Create(Object, Info, {CFrame = TargetCFrame}):Play()
	task.wait(0.1)
until (Object.Position - Vector3.zero).Magnitude > 100
1 Like

It does, but the loop is ran a lot of times so i think 7 percent is to be expected. But yeah it is too much and im trying to maximize performance.

same performance with the script you gave on aswell, do you have any recommendations on other ways to improve the performance?

1 Like

Are you sure that this high percentage is only caused by this loop?
You do a different thread loop for each bullet? Each bullet has its own loop?

It is weird because, i also made a infinite loop that run 10/s in the game i’m working on, and this loop is handling much more things than you including +20 different tweens, and the script never go above 1% so idk.

1 Like

different thread loop for each bullet.
do note that theres a thousand bullets.

1 Like

Oh yeah, so that’s why…
You should try to use a single loop and CollectionService like this:

--[[ Roblox Services ]]--
local CollectionService = game:GetService("CollectionService")
local TweenService = game:GetService("TweenService")

local BulletInfo = TweenInfo.new(1, Enum.EasingStyle.Linear)

--[[ Main Tables ]]--
local TableBullet = {}

--------------------------------------------------------------------------
--------------------------------------------------------------------------

--[[ Local Functions ]]--
local function TweenBullet(Bullet)
	if (Bullet.Object.Position-Vector3.zero).Magnitude > 100 then
		table.remove(TableBullet, TableBullet[Bullet])
	else
		TweenService:Create(Bullet.Object, BulletInfo, {CFrame = Bullet.Object.CFrame * CFrame.new(-Bullet.Speed*10,0,0)}):Play()
	end
end

--------------------------------------------------------------------------
--------------------------------------------------------------------------

--[[ Connections Setup ]]--
CollectionService:GetInstanceAddedSignal("Bullet"):Connect(function(Bullet)
	if Bullet:FindFirstAncestorWhichIsA("Workspace") then
		table.insert(TableBullet, Bullet)
	end
end)

CollectionService:GetInstanceRemovedSignal("Bullet"):Connect(function(Bullet)
	table.remove(TableBullet, TableBullet[Bullet])
end)

--[[ Loop Setup ]]--
while task.wait(0.1) do
	for _, Bullet in pairs(TableBullet) do
		TweenBullet(Bullet)
	end
end

Iterating through thousands objects may lag, but you can split it to one loop and one table per player/weapon which still is better than a new thread loop for every single bullet… then it should reduce the ressources taken by half and down the script rate to 0.1s * number of players.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.