2D RPG style sprite movement?

  1. What do you want to achieve? Keep it simple and clear!
    I want to create a game, not necessarily an rpg game, just a game that utilises the 2d top down sprite aspect of an rpg game, like purple skittles did. I’m okay with the movement part its more the animation of the 2d sprite part. I am using spritesheets and billboard guis as the character

  2. What is the issue? Include screenshots / videos if possible!
    I can’t figure out the movement, I am a very amateur coder and do not have much experience but I thought I could figure it out, however there are barely any tutorials or devforum posts covering this, there is probably an easy solution but I have been trying for 4 days to no avail.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I have looked all over the developer hub and could not find anything, I have recoded this countless times, using User Input System, using move direction and still cannot find a reliable solution, I have found a script that kind of works but it is very messy and sometimes fails to play the animation. here is the script in its entirety:

local plrSprite = game.Players.LocalPlayer.Character.HumanoidRootPart.plr.plrGui.plrSprite
local plr = game.Players.LocalPlayer.Character
local player = game.Players.LocalPlayer
local RunService = game:GetService('RunService')
local ContextActionService = game:GetService('ContextActionService')
local debounce = false
local debounce2 = false
local leftValue, rightValue, upValue, downValue = 0, 0, 0, 0
local directionFacing = nil
local imageSize = 250
local idleFrame = 0
local priority = nil
local walking = false

local idleFrames = {
	Vector2.new(0, 0)
}

local runFrames = {
	Vector2.new(512, 0); Vector2.new(0,0);  Vector2.new(768,0); Vector2.new(0,0)
}

local runFramesLeft = {
	Vector2.new(768, 512); Vector2.new(256, 512); Vector2.new(1024, 512); Vector2.new(256, 512)
}

local runFramesRight = {
	Vector2.new(512, 512); Vector2.new(0, 512); Vector2.new(768, 512); Vector2.new(0, 512)
}

local runFramesUp = {
	Vector2.new(512, 256); Vector2.new(0,256);  Vector2.new(768,256); Vector2.new(0,256)
}

local function animation()
	if priority == "Right" then
		local runningState = false
		while rightValue == 1 do
			wait()
			imageSize = 250
			plrSprite.ImageRectSize = Vector2.new(imageSize,250)
			directionFacing = 512
			idleFrame = 0
			for i = 1, #runFramesRight do
				if rightValue == 1 and runningState == false then
					if priority ~= "Right" then return end
					runningState = true
					plrSprite.ImageRectOffset = runFramesRight[i]
					wait(.15)
					runningState = false
				end
			end
		end
	elseif priority == "Left" then
		local runningState = false
		while leftValue == 1 do
			wait()
			imageSize = -250
			plrSprite.ImageRectSize = Vector2.new(imageSize,250)
			directionFacing = 512
			idleFrame = 256
			for i = 1, #runFramesLeft do
				if leftValue == 1 and runningState == false then
					if priority ~= "Left" then return end
					runningState = true
					plrSprite.ImageRectOffset = runFramesLeft[i]
					wait(.15)
					runningState = false
				end
			end	
		end	
	elseif priority == "Up" then
		local runningState = false
		while upValue == 1 do
			wait()
			imageSize = 250
			plrSprite.ImageRectSize = Vector2.new(imageSize,250)
			directionFacing = 256
			idleFrame = 0
			for i = 1, #runFramesUp do
				if upValue == 1 and runningState == false then
					if priority ~= "Up" then return end
					runningState = true
					plrSprite.ImageRectOffset = runFramesUp[i]
					wait(.15)
					runningState = false
				end
			end
		end
	elseif priority == "Down" then
		local runningState = false
		while downValue == 1 do
			wait()
			imageSize = 250
			plrSprite.ImageRectSize = Vector2.new(imageSize,250)
			directionFacing = 0
			idleFrame = 0
			for i = 1, #runFrames do
				if downValue == 1 and runningState == false then
					if priority ~= "Down" then return end
					runningState = true
					plrSprite.ImageRectOffset = runFrames[i]
					wait(.15)
					runningState = false
				end
			end
		end	
	end
end

--Functions to move(IK what this all means DW im competent)
local function onLeft(actionName, inputState)
	local runningState = false
	local triggeredWalk = false
	if inputState == Enum.UserInputState.Begin and player.Character.Humanoid.WalkSpeed > 0 then 
		leftValue = 1
		if walking == false then
			triggeredWalk = true
			walking = true
			priority = "Left"
			animation()
		end
	elseif inputState == Enum.UserInputState.End then
		leftValue = 0
		wait()
		if priority == "Left" then
			if downValue == 1 then
				priority = "Down" 
				animation()
				return
			elseif rightValue == 1 then
				priority = "Right" 
				animation()
				return
			elseif upValue == 1 then
				priority = "Up" 
				animation()
				return
			else
				priority = nil
				return
			end	
		end
		if walking == true and triggeredWalk == true then
			triggeredWalk = false
			walking = false
		end	
	end
end

local function onRight(actionName, inputState)
	local runningState = false
	local triggeredWalk = false
	if inputState == Enum.UserInputState.Begin and player.Character.Humanoid.WalkSpeed > 0 then
		rightValue = 1
		if walking == false then
			triggeredWalk = true
			walking = true
			priority = "Right"
			animation()
		end
	elseif inputState == Enum.UserInputState.End then
		rightValue = 0
		wait()
		if priority == "Right" then
			if leftValue == 1 then
				priority = "Left" 
				animation()
				return
			elseif downValue == 1 then
				priority = "Down" 
				animation()
				return
			elseif upValue == 1 then
				priority = "Up" 
				animation()
				return
			else
				priority = nil
				return
			end	
		end
		if walking == true and triggeredWalk == true then
			triggeredWalk = false
			walking = false
		end	
	end
end

local function uppies(actionName, inputState)
	local runningState = false
	local triggeredWalk = false
	if inputState == Enum.UserInputState.Begin and player.Character.Humanoid.WalkSpeed > 0 then
		upValue = 1
		if walking == false then
			triggeredWalk = true
			walking = true
			priority = "Up"
			animation()
		end
	elseif inputState == Enum.UserInputState.End then
		upValue = 0
		wait()
		if priority == "Up" then
			if leftValue == 1 then
				priority = "Left" 
				animation()
				return
			elseif rightValue == 1 then
				priority = "Right" 
				animation()
				return
			elseif downValue == 1 then
				priority = "Down" 
				animation()
				return
			else
				priority = nil
				return
			end	
		end
		if walking == true and triggeredWalk == true then
			triggeredWalk = false
			walking = false
		end	
	end
end

local function onDownXDXDXD(actionName, inputState)
	local runningState = false
	local triggeredWalk = false
	if inputState == Enum.UserInputState.Begin and player.Character.Humanoid.WalkSpeed > 0 then
		downValue = 1
		if walking == false then
			triggeredWalk = true
			walking = true
			priority = "Down"
			animation()
		end
	elseif inputState == Enum.UserInputState.End then
		downValue = 0
		wait()
		if priority == "Down" then
			if leftValue == 1 then
				priority = "Left" 
				animation()
				return
			elseif rightValue == 1 then
				priority = "Right" 
				animation()
				return
			elseif upValue == 1 then
				priority = "Up" 
				animation()
				return
			else
				priority = nil
				return
			end	
		end
		if walking == true and triggeredWalk == true then
			triggeredWalk = false
			walking = false
		end	
	end
end


local function onUpdate()
	if player.Character and player.Character:FindFirstChild('Humanoid') then
		local moveDirectionX = rightValue - leftValue
		local moveDirectionZ = downValue - upValue
		player.Character.Humanoid:Move(Vector3.new(moveDirectionX,0,moveDirectionZ), false)
		if moveDirectionX == 0 and moveDirectionZ == 0 and debounce == false then
			if walking == true then
				walking = false
			end	
			debounce = true
			plrSprite.ImageRectOffset = Vector2.new(idleFrame, directionFacing)
			plrSprite.ImageRectSize = Vector2.new(imageSize, 250)
			wait(.5)
			debounce = false

		end	
	end	
end

RunService:BindToRenderStep('Control', Enum.RenderPriority.Input.Value, onUpdate)

ContextActionService:BindAction('Left', onLeft, true, 'a', Enum.KeyCode.Left, Enum.KeyCode.DPadLeft)
ContextActionService:BindAction('Right', onRight, true, 'd', Enum.KeyCode.Right, Enum.KeyCode.DPadRight)
ContextActionService:BindAction('Up', uppies, true, 'w', Enum.KeyCode.Up, Enum.KeyCode.DPadUp)
ContextActionService:BindAction('Down', onDownXDXDXD, true, 's', Enum.KeyCode.Down, Enum.KeyCode.DPadDown)

A solution would be much appreciated, i really want to carry on with this game and this is a roadblock I have yet to pass.
here is a link to the game if it helps (ignore the title and the janky sprite work I havent thought of a name yet): dream not found - Roblox

3 Likes