TweenService causing lag (10 lines)

		local NewBulletHole = RS:WaitForChild("BulletHole"):Clone()
		NewBulletHole.CFrame = CFrame.new(BulletResult.Position, BulletResult.Position + BulletResult.Normal)
		NewBulletHole.Parent = workspace

		task.spawn(function() -- this function is causing lag
			task.wait(6)
			local BulletHoleTween = TweenService:Create(NewBulletHole.Decal, TweenInfo.new(10), {Transparency = 1})
			BulletHoleTween:Play()
			BulletHoleTween.Completed:Connect(function() NewBulletHole:Destroy() end)
		end)

I’m scripting a gun system, and the code above places a bullet hole then waits 6 seconds before tweening and destroying the bullet hole

Whenever I run the game, it causes lag. Whenever I disable the function, the lag stops entirely

Any help is appreciated

1 Like

Try playing the tween without creating a new thread. Tweens automatically run in their own thread by nature, thus eliminating the need for task.spawn().

1 Like

task.spawn() is needed to wait 6 seconds before deleting the bullet hole. Without task.spawn(), it would pause the entire function

The tween should be playing after 6 seconds, then the bullet hole needs to be destroyed after the tween finishes

2 Likes

Ah, that’s my mistake then. Perhaps task.delay() may be more performant?

Out of curiosity, why create a separate thread at all? Not sure how your gun system operates, but it would make sense to me to use an event-based approach here to determine when the bullet impacts an object.

The bullet is not a physical object, it’s just a raycast so I don’t need to use an event to detect if it impacts an object
It’s just “if RaycastResult” or “if RaycastResult.Instance”

when using task.wait(6), it would pause the entire script, so I put it in a task.spawn function

		local BulletHoleTween = TweenService:Create(NewBulletHole.Decal, TweenInfo.new(10), {Transparency = 1})
		
		task.delay(6, function()
			BulletHoleTween:Play()
			BulletHoleTween.Completed:Connect(function()
				NewBulletHole:Destroy()
			end)
		end)

Did I write this properly? I haven’t used task.delay before

Yup, seems like it should work from here.

It functions as intended, but the lag is still visible

Are you tweening this on the client or server? Excessive tweening on the server can cause lag and other tween objects to slow down. Tweening objects client-side is best for performance. You also have the tween duration set to 10 by doing “TweenInfo.new(10)”

Try to identify the BulletHole texture/model once with WaitForChild and then clone the same object you’ve already identified instead of waiting for an instance every time. This may not make any difference, but it is optimal for your code. I also made a minor change to your Tween.Completed event, you can set a variable to it if you want it to yield the tween state.

local BulletHole = RS:WaitForChild("BulletHole") -- at the top of your script

local NewBulletHole = BulletHole:Clone()
NewBulletHole.CFrame = CFrame.new(BulletResult.Position, BulletResult.Position + BulletResult.Normal)
NewBulletHole.Parent = workspace

task.delay(6, function()
	local BulletHoleTween = TweenService:Create(NewBulletHole.Decal, TweenInfo.new(10), {Transparency = 1})
	BulletHoleTween:Play()
	BulletHoleTween.Completed:Wait()
	NewBulletHole:Destroy()
end)

It’s tweened on the server. It’s probably best that you mentioned this because I would imagine hundreds of bullet holes being spawned and tweened at the same time for every user in the server would be very performance heavy

Anyways, switching it to the client and I’ll let you know if it works

I switched everything over to the client, tried some debugging, and play tested multiple times

Here is the current script, it’s lagging still

		local MyParams = RaycastParams.new()
		MyParams.FilterDescendantsInstances = {ObjectsToIgnore, Char}
		MyParams.FilterType = Enum.RaycastFilterType.Blacklist

		local BulletResult = workspace:Raycast(Head.Position, (Mouse.Hit.Position - Head.Position).Unit * 500, MyParams)

		if BulletResult and BulletResult.Instance and AmmosList.Ammo.Value > 0 then

			local NewBulletHole = RS:WaitForChild("BulletHole"):Clone()
			NewBulletHole.CFrame = CFrame.new(BulletResult.Position, BulletResult.Position + BulletResult.Normal)
			NewBulletHole.Parent = workspace

			task.delay(6, function()
				local BulletHoleTween = TweenService:Create(NewBulletHole.Decal, TweenInfo.new(10), {Transparency = 1})
				BulletHoleTween:Play()
				BulletHoleTween.Completed:Wait()
				NewBulletHole:Destroy()
			end)
		end

Another thing:
The lag only happens when the tween starts. I removed the “BulletHoleTween:Play()” and the game never lagged.

Try to destroy the TweenBase to clear memory leak.

local MyParams = RaycastParams.new()
MyParams.FilterDescendantsInstances = {ObjectsToIgnore, Char}
MyParams.FilterType = Enum.RaycastFilterType.Blacklist

local BulletResult = workspace:Raycast(Head.Position, (Mouse.Hit.Position - Head.Position).Unit * 500, MyParams)

if BulletResult and BulletResult.Instance and AmmosList.Ammo.Value > 0 then

	local NewBulletHole = RS:WaitForChild("BulletHole"):Clone()
	NewBulletHole.CFrame = CFrame.new(BulletResult.Position, BulletResult.Position + BulletResult.Normal)
	NewBulletHole.Parent = workspace

	task.delay(6, function()
		local BulletHoleTween = TweenService:Create(NewBulletHole.Decal, TweenInfo.new(10), {Transparency = 1})
		BulletHoleTween:Play()
		BulletHoleTween.Completed:Wait()
		NewBulletHole:Destroy()
		BulletHoleTween:Destroy()
	end)
end

This actually is not necessary seeing an event connection is never established, and as soon as BulletHoleTween is out of scope, it will be cleaned up from memory. Nothing else in the code references the tween object, so therefor it becomes eligible to get collected by the garbage collector.

1 Like

I just found the issue after about 2-3 hours of debugging (and googling), somehow there was a humanoid in the workspace which basically made every single tween lag super badly

This is very common for some reason and I’m really considering making a plugin to prevent this.