Turret Rotation Issue with WASD – Keeps Rotating in Same Direction After Changing Keys

Hi everyone,
I’m currently working on a turret system in Roblox Studio where the player can control the turret’s rotation using the W and S keys:

  • W rotates the turret to the left
  • S rotates the turret to the right

The problem I’m facing is with how the turret responds when switching between inputs. For example:

If I hold down the W key, the turret rotates to the left, as expected. But when I release W and press S, the turret continues rotating to the left, instead of switching direction and rotating to the right.

It feels like the previous input (W) is still being processed, even after switching to S. The turret doesn’t change direction immediately — it just keeps spinning the way it was before.

I believe this might be related to how the input is being tracked or how the rotation is applied each frame, but I’m not sure how to fix it.

(I’m new to Roblox Studio, so any help or tips are greatly appreciated!)

Here’s the code I’m using:

Server Script:

local TI = TweenInfo.new(10, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, 0, false, 0)
local left  = game:GetService("TweenService"):Create(workspace.Part, TI, {Rotation = Vector3.new(0, 360, 0)})
local right = game:GetService("TweenService"):Create(workspace.Part, TI, {Rotation = Vector3.new(0, -360, 0)})

left.Completed:Connect(function(state)
	if state == Enum.PlaybackState.Completed then
		left:Play()
	end
end)

local StartActions = {
	ActionW = function(player)
		print("+W")
		if right then right:Pause() end
		left = game:GetService("TweenService"):Create(workspace.Part, TI, {Rotation = workspace.Part.Rotation + Vector3.new(0, 360, 0)})
		left:Play()
	end;
	ActionA = function(player)
		print("+A")
	end;
	ActionS = function(player)
		print("+S")
		if left then left:Pause() end
		right = game:GetService("TweenService"):Create(workspace.Part, TI, {Rotation = workspace.Part.Rotation + Vector3.new(0, -360, 0)})
		right:Play()
	end;
	ActionD = function(player)
		print("+D")
	end;
}

local EndActions = {
	ActionW = function(player)
		print("-W")
		left:Pause()
	end;
	ActionA = function(player)
		print("-A")
	end;
	ActionS = function(player)
		print("-S")
		right:Pause()
	end;
	ActionD = function(player)
		print("-D")
	end;
}

game.ReplicatedStorage.TurretRemote.OnServerEvent:Connect(function(player, began, key)
	if began then
		StartActions["Action" .. key](player)
	else
		EndActions["Action" .. key](player)
	end
end)

LocalScript:

local UIS = game:GetService("UserInputService")

UIS.InputBegan:Connect(function(input)
	if string.find("W A S D", input.KeyCode.Name) then
		game.ReplicatedStorage.TurretRemote:FireServer(true, input.KeyCode.Name)
	end
end)

UIS.InputEnded:Connect(function(input)
	if string.find("W A S D", input.KeyCode.Name) then
		game.ReplicatedStorage.TurretRemote:FireServer(false, input.KeyCode.Name)
	end
end)

Has anyone experienced this issue before or know how to properly handle smooth directional changes when using keyboard input?

2 Likes

I’d recommend using some CFrame math and a HeartBeat + Lerp to smooth the movement, use some Variables to determine the X , Y aswell.

On the other hand I believe your issue is you need to :Stop() the other tween that is running as two tweens on the same block conflict i believe.

1 Like
local RunService = game:GetService("RunService")

local ROTATION_SPEED = 60 -- degrees per second
local rotatingLeft = false
local rotatingRight = false

RunService.Heartbeat:Connect(function(dt)
	local part = workspace.Part
	if rotatingLeft then
		part.CFrame = part.CFrame * CFrame.Angles(0, math.rad(ROTATION_SPEED * dt), 0)
	elseif rotatingRight then
		part.CFrame = part.CFrame * CFrame.Angles(0, -math.rad(ROTATION_SPEED * dt), 0)
	end
end)

game.ReplicatedStorage.TurretRemote.OnServerEvent:Connect(function(player, began, key)
	if key == "W" then
		rotatingLeft = began
	elseif key == "S" then
		rotatingRight = began
	end
end)

is this good?

Seems to be, give it a try and let me know how it functions

1 Like

ok its good
Thanks for the advice
:3

1 Like

The issue comes from the fact that the Tween objects, left and right, persist even after you start a new action, leading to overlapping or conflicting behavior. To fix this, you need to ensure that any currently active tween is completely canceled before starting a new one. Right now, you only pause them, which doesn’t fully reset their playback state.

Instead of just pausing the active tween, use .Cancel() on the running tween (e.g., left:Cancel() or right:Cancel()). This ensures it’s fully terminated before creating a new tween

i just need to replace :pause() with Cancel:()?

Yes, Replacing :Pause() with :Cancel() should address the issue. Unlike Pause(), which just halts the tween temporarily, Cancel() completely stops it and resets its playback state. This way, when you create and play a new tween, there won’t be any lingering effects or conflicts from the previous one.

what is better Tweens or Cframe?

If you want smooth, animated movement with easing effects, Tweens are great since they handle transitions over time automatically. On the other hand, CFrame gives you precise, real-time control over positioning and rotation, making it better for physics-based interactions or frame-by-frame adjustments.

1 Like