How do I smoothly move GUIs with arrow keys?

I’ve been recently trying to make a 2D bullet-hell shooting game using GUI’s on Roblox but I’ve been getting this issue where the player moves very badly. I need the player to move and also when you hold the arrow keys, instead of moving once, it keeps moving until you release it. I also know how to use UserInputService but it just handles the keyboard input once, not when holding. Any help? Thanks for reading.

1 Like

Can’t speak to the player moving badly because you aren’t showing the code that handles that so it wouldn’t be possible. For the holding the keys down take a look at this post:

2 Likes

sorry, my bad. here is the code that i’ve been using for all of this:

local UIS = game:GetService("UserInputService")
local Keys = {
	Up = Enum.KeyCode.Up;
	Left = Enum.KeyCode.Left;
	Right = Enum.KeyCode.Right;
	Down = Enum.KeyCode.Down
}
local ButtonToMove = script.Parent 

UIS.InputBegan:Connect(function(input)
	local LocaleKeycode = input.KeyCode
	if LocaleKeycode == Keys.Up then
		ButtonToMove.Position += UDim2.fromScale(0,-0.05)
	elseif LocaleKeycode == Keys.Left then
		ButtonToMove.Position += UDim2.fromScale(-0.05,0)
	elseif LocaleKeycode == Keys.Right then
		ButtonToMove.Position += UDim2.fromScale(0.05,0)
	elseif LocaleKeycode == Keys.Down then
		ButtonToMove.Position += UDim2.fromScale(0,0.05)
	end
end)

and sorry but the post you sent regarding my issue didn’t work well for my game since i was missing a couple variables. if you have tested the code above, the player moves very stiff, and i want it to be smooth and steady to control

I would avoid using .fromScale as it means players on different resolutions move at different speeds. Using .fromOffset means you’re using pixels, rather than a percentage of the display size.

1 Like

Well, the size of the game screen is also different from device to device, so using fromScale is correct in this case.

When that is said, Hi!

You’re almost there with the movement. You could possibly do this:

local MovementInterval = 0.01
local MovementDistance = 0.05
local KeysDown = {}

UIS.InputBegan:Connect(function(input, gameprocessed)
	if gameprocessed then return end
	local LocaleKeycode = input.KeyCode
	if LocaleKeycode == Keys.Up then
		if KeysDown[LocaleKeycode] then return end -- Just makes sure that we cannot send two InputBegan of the same type, before we at least have had a InputEnded of the same type, just a debounce to be fair.
		KeysDown[LocaleKeycode] = true
		repeat
			ButtonToMove.Position += UDim2.fromScale(0,-MovementDistance)
			task.wait(MovementInterval)
		until not KeysDown[LocaleKeycode]
	elseif LocaleKeycode == Keys.Left then
	--Repeat yourself for the rest of the keys
	end
end)
UIS.InputEnded:Connect(function(input, gameprocessed)
	if gameprocessed then return end
	local LocaleKeycode = input.KeyCode
	if LocaleKeycode == Keys.Up then
		KeysDown[LocaleKeycode] = nil
	elseif LocaleKeycode == Keys.Left then
	--Repeat yourself for the rest of the keys
	end
end)

Edit: Just be aware, that with this method the movement-directions is not in sync, meaning that the movement in two directions wont be done at the exact same moment, since it’s multiple repeat loops.

Just updated your code a bit to take care of multiple movement:

local MovementInterval = 0.01
local MovementDistance = 0.005
local KeysDown = {}
local downCount = 0

UIS.InputBegan:Connect(function(input, gameprocessed)
	if gameprocessed then return end
	local LocaleKeycode = input.KeyCode
	
	if LocaleKeycode == Keys.Up or LocaleKeycode == Keys.Down or LocaleKeycode == Keys.Right or LocaleKeycode == Keys.Left then
		if KeysDown[LocaleKeycode] then return end 
		
		KeysDown[LocaleKeycode] = true
		downCount += 1
		if downCount > 1 then return end
		
		repeat
			if KeysDown[Keys.Up] then
				ButtonToMove.Position += UDim2.fromScale(0,-MovementDistance)
			end
			if KeysDown[Keys.Down] then
				ButtonToMove.Position += UDim2.fromScale(0,MovementDistance)
			end
			if KeysDown[Keys.Right] then
				ButtonToMove.Position += UDim2.fromScale(MovementDistance,0)
			end
			if KeysDown[Keys.Left] then
				ButtonToMove.Position += UDim2.fromScale(-MovementDistance,0)
			end
			task.wait(MovementInterval)
		until downCount < 1		
	end
end)
UIS.InputEnded:Connect(function(input, gameprocessed)
	if gameprocessed then return end
	local LocaleKeycode = input.KeyCode
	if LocaleKeycode == Keys.Up or LocaleKeycode == Keys.Down or LocaleKeycode == Keys.Right or LocaleKeycode == Keys.Left then
		KeysDown[LocaleKeycode] = nil
		downCount -= 1
	end
end)