Making a turret faster/slower based on speed

I have this problem that I don’t really know how to begin to solve. I created a turret that shoots at players and it works fine. I use TweenService to make the turret rotate towards players’ heads. I scripted it so the turret waits to turn before shooting. The fire rate is slower when it turns as it has to wait. However, if a player targeted by it even moves slightly (for example from an idle animation) the fire rate will slow down as it has to tween to the new position of the player head. It will take the same amount of time to rotate small distances vs larger distances. How would I make it so that the turret’s rotational speed depends on the distance it needs to rotate towards a target?
I’ve tried to make the turret not tween when it doesn’t need to, but again, this doesn’t work as a slight movement can cause it to need to tween again.

Test with Dummy:


Test with a player:

As you can see, the fire rate for the Dummy is faster since it does not move at all.
Code used to tween:

	local tweeninfo = TweenInfo.new(.25,Enum.EasingStyle.Linear,Enum.EasingDirection.InOut)
	local LookAt = Vector3.new(target.Position.X, Turner.Position.Y, target.Position.Z)
	if Turner.CFrame ~= CFrame.lookAt(Turner.Position, LookAt) then
		local goal = {}
		local goal2 = {}
		goal.CFrame = CFrame.lookAt(Turner.Position, LookAt)
		goal2.CFrame = CFrame.lookAt(Turner2.Position, target.Position)
		
		local TurnerTween = TS:Create(Turner,tweeninfo,goal)
		local TurnerTween2 = TS:Create(Turner2,tweeninfo,goal2)
		
		TurnerTween:Play()
		TurnerTween2:Play()
		TurnerTween2.Completed:Wait()
	end

“Turner” and “Turner2” are invisible parts welded to the turret to make it turn.

You could possibly wrap the part where you tween the turret in a coroutine to stop it from yielding the script

No, I can already do that by removing the .Completed:Wait() event, but I want the tween’s speed to be based on the distance it needs to rotate

Using tween services might be the not recommended solution here as you said you will need to change the 0.25 and possible create a new tween info every time which is doable but it just feels odd in my opinion.

Anyways, to ensure constant turret speed you can use CFrame lerping between the turrets current CFrame and the goal CFrame through the following formula by measuring the angular distance between current and goal. I believe you can also apply this to tween service but well it’s up to you.

		local adjustedLerpAlpha
		if step and self.ConstantSpeed then
			local angularDistance = VectorUtil.AngleBetween(currentRotation.LookVector,goalRotationCFrame.LookVector)
			local estimatedTime = self.AngularSpeed/angularDistance
			adjustedLerpAlpha = math.min(step*estimatedTime,1)
		elseif step then
--other stuff
end

Also I don’t recommend this.

When working with numbers like CFrames you will always run into floating point errors hence it’s not exactly sure if this condition can be true at all, I would recommend measuring the angle instead if its in a certain range to see if the turret is pointing close to the target to avoid the floating point error.

1 Like

I’ll definitely try your solution and the module you made when I get a chance to. Thank you. I’ll mark this as a solution if it works.