How would I solve this problem?

Currenty I’m trying to make a 2D Character Animation System, where if you press the W A S or D keys, the character will begin moving in the according direction. Whenever I press one of these keys, the character has a chance of violently vibrating. I’m not sure if this is Roblox Studio failing to update the character position in time or a misuse of something on my part.

Video Example:

MovementScript: This is a client script!

--Variables
local UserInputService = game:GetService("UserInputService")
local Character = game.Workspace:WaitForChild("2DCharacter")

local ForwardWalking = false
local LeftWalking = false
local RightWalking = false
local BackwardWalking = false


local function WkeyPressed()
	while BackwardWalking do
		wait(.00000000001)
		Character.Position = Vector3.new(Character.Position.X - 1,Character.Position.Y, Character.Position.Z)
	
	end
end

local function AkeyPressed()
	while LeftWalking do
		wait(.00000000001)
		Character.Position = Vector3.new(Character.Position.X ,Character.Position.Y, Character.Position.Z - 1)

	end
end

local function SkeyPressed()
	while ForwardWalking do
		wait(.00000000001)
		Character.Position = Vector3.new(Character.Position.X + 1,Character.Position.Y, Character.Position.Z)

	end
end

local function DkeyPressed()
	while RightWalking do
		wait(.00000000001)
		Character.Position = Vector3.new(Character.Position.X ,Character.Position.Y, Character.Position.Z + 1)

	end
end


local function Idle()
	while not BackwardWalking or LeftWalking or RightWalking or ForwardWalking do
		wait()
 --Put something here
	end
end

--Input & Output 


UserInputService.InputBegan:Connect(function(input, gameProcessedEvent) --Input
	if input.KeyCode == Enum.KeyCode.W then
		BackwardWalking = true
		WkeyPressed()
	elseif
		input.KeyCode == Enum.KeyCode.A then
		LeftWalking = true
		AkeyPressed()
	elseif 
		input.KeyCode == Enum.KeyCode.S then
		ForwardWalking = true
		SkeyPressed()
	elseif 
		input.KeyCode == Enum.KeyCode.D then
		RightWalking = true
		DkeyPressed()
	end
end)

UserInputService.InputEnded:Connect(function(input, gameProcessedEvent) -- Output
	if input.KeyCode == Enum.KeyCode.W then
		BackwardWalking = false
		Idle()
	elseif 
		input.KeyCode == Enum.KeyCode.A then
		LeftWalking = false
		Idle()
	elseif 
		input.KeyCode == Enum.KeyCode.S then
		ForwardWalking = false
		Idle()
	elseif 
		input.KeyCode == Enum.KeyCode.D then
		RightWalking = false
		Idle()
	end
end)

CameraScript: This is a client script!

--Variables
local Character = game.Workspace:WaitForChild("2DCharacter")

local CameraPart2 = Character.CameraAttachment
local Camera = game.Workspace.CurrentCamera
local FocusPart2 = Character.CameraAttachment
local Player = game:GetService("Players").LocalPlayer


--Whenever the Customize button is clicked it fires this function
while true do
	wait()
	--Sets cameras cframe and focus
	Camera.CameraType = "Scriptable"
	Camera.CameraSubject = CameraPart2
	Camera.Focus = FocusPart2.WorldCFrame
	Camera.CFrame = FocusPart2.WorldCFrame
end

All help and input is appreciated, thank you!

2 Likes

I would try using task.wait() instead of wait() its more accurate

and on the camera updates I would put those in a renderstepped function without any waits

see how it reacts then

1 Like

Both are a mistake in this case.

This. Your user input processing code should also have zero wait() calls of any flavor and zero while do loops. Input event handlers start their own Lua threads so having yielding calls or loops in them creates the chaos you’re currently experiencing. Just set and clear your directional boolean flags on the input began and ended events, and then separately bind to RenderStep with input priority and process the flags to generate that frame’s move direction based on the bools.

1 Like

Can you re say this? I’m getting confused on your wording.

1 Like

they are saying to totally write this different and to put it in a renderstepped function no loops

1 Like

As I can’t test this it may not be the best way of doing it(there are a few more) but here is an example I of how it could be setup with renderstepped and changing your previous code a bit no loops

--Variables
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService('RunService')  -- added this for render function below
local Character = game.Workspace:WaitForChild("2DCharacter")

local CameraPart2 = Character.CameraAttachment
local Camera = game.Workspace.CurrentCamera
local FocusPart2 = Character.CameraAttachment
local Player = game:GetService("Players").LocalPlayer

Camera.CameraType = "Scriptable"  -- sets the camera up just once renderstepped below will set cframes
Camera.CameraSubject = CameraPart2


local ForwardBackwardWalking = 0  -- changed so they can be set to either 1 or 0 or -1
local LeftRightWalking = 0


--[[  -- might not need this if you do then it will need changed
local function Idle()   -- 
	while not BackwardWalking or LeftWalking or RightWalking or ForwardWalking do
		wait()
		--Put something here
	end
end
--]]
--Input & Output 


UserInputService.InputBegan:Connect(function(input, gameProcessedEvent) --Input
	if input.KeyCode == Enum.KeyCode.W then
		ForwardBackwardWalking = -1
	elseif input.KeyCode == Enum.KeyCode.S then
		ForwardBackwardWalking = 1
	elseif input.KeyCode == Enum.KeyCode.A then
		LeftRightWalking = -1
	elseif input.KeyCode == Enum.KeyCode.D then
		LeftRightWalking = 1
	end
end)

UserInputService.InputEnded:Connect(function(input, gameProcessedEvent) -- Output
	if input.KeyCode == Enum.KeyCode.W then
		-- this will set to 0 only if its curretly set to this keys value else it will just leave it alone since the other key maybe active
		ForwardBackwardWalking = ForwardBackwardWalking == -1 and 0 or ForwardBackwardWalking  
	elseif input.KeyCode == Enum.KeyCode.S then
		ForwardBackwardWalking = ForwardBackwardWalking == 1 and 0 or ForwardBackwardWalking
	elseif input.KeyCode == Enum.KeyCode.A then
		LeftRightWalking = LeftRightWalking == -1 and 0 or LeftRightWalking
	elseif input.KeyCode == Enum.KeyCode.D then
		LeftRightWalking = LeftRightWalking == 1 and 0 or LeftRightWalking
	end
end)


RunService.RenderStepped:Connect(function()
	Character.Position = Vector3.new(Character.Position.X + ForwardBackwardWalking,Character.Position.Y, Character.Position.Z + LeftRightWalking)
	--Sets cameras cframe and focus
	Camera.Focus = FocusPart2.WorldCFrame
	Camera.CFrame = FocusPart2.WorldCFrame
end)
2 Likes

Writing controls like this with loops and waits in each button function is going to cause you infinite pain, since you cannot directly control the order in which each function resumes. This could lead to the situation you’re seeing. Instead, it is typical to have each button function only control a variable, kind of like the ones you already have, and then doing the actual updates to the position in a single function which is looped (or even better bound to Stepped / Heartbeat) and has a single specific location where it waits. This makes the timing situation much more predictable.


image

1 Like

Nyonic’s followup code example is exactly the pattern I typically use for things like vehicles, and the sort of setup I had in mind.

1 Like