Barrage effect speed changes depending on players fps

When the player barrages the arms should go at a constant speed not depending on the players fps. However, when changing the fps, the arms will go fast or slow depending on the fps.

60 fps: Desktop 2022.06.21 - 16.48.35.01.mp4 on Vimeo
200 fps: Desktop 2022.06.21 - 16.48.57.02.mp4 on Vimeo
30 fps: Desktop 2022.06.21 - 16.49.21.03.mp4 on Vimeo

Script:

local function TweenArms(arm,char,rightorleft)
			local n1,n2
			
			coroutine.resume(coroutine.create(function()
				local armStartCf = arm:GetPivot()
				local timeElapsed = 0

				local pivotCFrame = CFrame.new(makeattachments(char).WorldPosition) 

				if rightorleft == "left" then
					n1,n2 = -3,-1
				else
					n1,n2 = 1,3
				end

				local rndCF = CFrame.new(rnd:NextNumber(n1,n2),rnd:NextNumber(-3.5,3.5),rnd:NextNumber(-2,2.5))

				local speed = 0.55
				local duration = (armStartCf.p - pivotCFrame.p).Magnitude / speed
				local tweenDelay = wait()

				timeElapsed = 0

				while timeElapsed < duration do
					local progress = timeElapsed / duration
					local pointAtTimeElapsed = quadBezier(progress,armStartCf.p,(armStartCf * rndCF).p, pivotCFrame.p)
					local lookAt = quadBezier(progress+0.01,armStartCf.p,(armStartCf * rndCF).p, pivotCFrame.p)

					if timeElapsed == 0 then
						arm:PivotTo(CFrame.new(pointAtTimeElapsed,quadBezier(progress+.01,armStartCf.p,(armStartCf * rndCF).p, pivotCFrame.p)) * CFrame.Angles(math.rad(90),0,0))  
						--elseif timeElapsed == speed then
						--	for _,v in pairs(arm:GetChildren()) do
						--		ts:Create(v,TweenInfo.new(1.1),{Transparency = 1}):Play()
						--	end
					end

					timeElapsed += speed
					if rightorleft == "left" then
						ts:Create(arm,TweenInfo.new(tweenDelay),{arm:PivotTo(CFrame.new(pointAtTimeElapsed,lookAt) * CFrame.Angles(rad(-270),0,0))}):Play()
					else
						ts:Create(arm,TweenInfo.new(tweenDelay),{arm:PivotTo(CFrame.new(pointAtTimeElapsed,lookAt) * CFrame.Angles(rad(-90),0,rad(-180)))}):Play()
					end
					task.wait()
				end
				arm:Destroy()
			end))
			
		end

That’s a consequence of using task.wait(), it’s essentially the same as RunService.Heartbeat:Wait().
If you need to account for its variable duration then you should include its value somewhere in the calculation.

https://developer.roblox.com/en-us/api-reference/event/RunService/Heartbeat
Check the example here for more information.

In addition to this, task.wait() also returns the time the wait took. You may use this, a “fists per second”/“delay per fist” value and some simple math to decide when a new fist should be thrown.