Best way to check if the player is moving & what direction they are moving?

Hello DevForum!

Title explains it all, I know I can possibly use humanoid.MoveDirection.Magnitude to check if they are walking, but finding the direction they are going is a bit weird.

I need 4 possible state, backwards, forwards, left, right. This is for playing an image animation, as the game is 3D but uses camera tricks and a tilted background to make it feel like a top down 2D RPG. I’m probably missing something, but for some reason I can’t find any good solutions out there for my specific case of 4 to check from.

If anybody can tell me some properties I can use to get these 4 states or other methods, that would be highly appreciated!

Thank you in advance :smiley:

12 Likes

use userinputservice and checking the player’s walkspeed?

2 Likes

What about mobile…? Walkspeed is ok, but I feel like it’s a bit of a hacky solution.

5 Likes

CFrames have a property called LookVector it’s a vector in the direction the CFrame is facing. You can use the HumanoidRootPart’s LookVector:

Character.HumanoidRootPart.LookVector --> Returns the vector in which the character is looking
1 Like

So, if this was the returned values, it’d be like this?

Vector3.new(1, 0, 0) -- Left
Vector3.new(-1, 0, 0) -- Right
Vector3.new(0, 0, 1) -- Forwards
Vector3.new(0, 0, -1) -- Backwards

Then also, how could I compare the Vectors to see if it’s over 1, 0, 0?

if you look into the control moduld of the player script i do think there is a function called GetMoveVector and you can check

local Vector=module:GetMoveVector
Vector.Z >= 1 --forward
Vector.Z <= 1 --backward
and so on...
2 Likes

Hm, I’ll try this but I have to go, I’ll let you know when I test it.

LookVector will return a vector relative to the front surface. So if you do LookVector * -1 you can get the inverse or back direction of the vector. You can use RightVector for the right and RightVector * -1 for the left vector.

EDIT: Also in response to getting a value over 1 you can multiply by an arbitrary number to increase the magnitude of the vector.

Hm, LookVector * -1 works, but how do I fit this in a conditional way? The equation will just return the backwards direction of the vector, which is not really telling me if they are going that way. This does seem interesting though, so I’ll look into it some more later.

There’s no such thing as “backwards.” Backwards relative to what? Relative to the x axis or z axis? Is backwards the negative or positive? It’s just too vague. If what you mean is you want when a player is moving backwards relative to themselves you can just check for input with the S key or whatever other input devices your game is for.

Humanoids have a property called MoveDirection that give you a unit vector of which direction the character is moving in. I would use this in conjunction with the function below:

function cardinalConvert(dir)
	local angle = math.atan2(dir.X, -dir.Z)
	local quarterTurn = math.pi / 2
	angle = -math.round(angle / quarterTurn) * quarterTurn
	
	local newX = -math.sin(angle)
	local newZ = -math.cos(angle)
	if math.abs(newX) <= 1e-10 then newX = 0 end
	if math.abs(newZ) <= 1e-10 then newZ = 0 end
	return Vector3.new(newX, 0, newZ)
end

Passing the MoveDirection to the cardinalConvert function should give you the vector you’re looking for. If the left/right are inverted, remove the negative in front of math.sin. If the up/down are inverted, remove the negative in front of the math.cos.

24 Likes

that is some serious math right there so how could i send a player backwards

3 Likes

I don’t know how to know when it MOVES, but I know you can use the torso CFrame and then just take the direction of the torso.

1 Like

This is very similar to this article, which I answered with some code examples and visual representations.

1 Like

Hm, it “kind of” works…

Here is what I mean.

	while true do -- Not going to actually do this, just for testing purposes
		wait(1)
		local humanoid = character:FindFirstChild("Humanoid")

        -- once again, for testing purposes 
		if not humanoid then return error("ERR: Humanoid required to load animations!") end
		local humanoidVector = cardinalConvert(humanoid.MoveDirection)

		if humanoidVector.X < 0 then print("Left") end
		if humanoidVector.X > 0 then print("Right") end
		if humanoidVector.Z > 0 then print("Forwards") end
		if humanoidVector.Z < 0 then print("Backwards") end
	end

The result I’m getting is this…


Left and right seem to work, but suddenly it’s saying backwards, then once you go back and forth the whole thing gets screwed up. I’m probably missing the point here or not understanding something, but this is a little weird.

5 Likes

The cardinalConvert function returned the correct vectors, it just left the zeroed-out axis with a super small number instead of 0 (it was about 1e-16 every time). You can replace your cardinalConvert with the updated cardinalConvert function above.

4 Likes

I made a version that is easier to read and 8 Dimensional (includes forward left, etc). I decided to share it with yall since it seems like it would help. Also, I recommend putting it into your Library Module.

function WorldMovingDirection(dir, MultiDirectional)
	--//Made by Juni_Purr and ImPremiumJay
	local NewMultiDirectional = MultiDirectional or false
	local angle = math.atan2(dir.X, -dir.Z)--Gives Angle
	local quarterTurn 
	if NewMultiDirectional then--If you want 8 Directional
		quarterTurn =	math.pi/4
	else--You want 4 Directional
		quarterTurn =	math.pi/2--Only want degrees 0-180 [x/2 is 4 dimensional, x/4 is 8 dimensional]
	end

	local CurrectVector = nil
	local MovingDirection
	if dir == Vector3.new(0,0,0) then return 'Idle' end--If they are standing still they are idle
	angle = -math.round(angle / quarterTurn) * quarterTurn

	local newX =math.round(-math.sin(angle))
	local newZ = math.round(-math.cos(angle))

	if math.abs(newX) <= 1e-10 then newX = 0 end
	if math.abs(newZ) <= 1e-10 then newZ = 0 end
	CurrectVector = Vector3.new(newX, 0, newZ)

	--Dictionary so you dont have to read numbers
	local Directions = {
		['Forward'] = Vector3.new(0, 0, -1),
		['Left'] = Vector3.new(-1, 0, 0),
		['Backwards'] = Vector3.new(0, 0, 1),
		['Right'] = Vector3.new(1, 0, 0)
	}

	if NewMultiDirectional then--If you want 8 directional movement
		Directions["ForwardLeft"] = Vector3.new(-1, 0, -1)
		Directions["ForwardRight"] = Vector3.new(1, 0, -1)
		Directions["BackwardLeft"] = Vector3.new(-1, 0, 1)
		Directions["BackwardRight"] = Vector3.new(1, 0, 1)
	end

	for Direction, Vector in Directions do
		-- Compare Directions
		if CurrectVector == Vector then--If players vector equals a vector in table Directions
			MovingDirection = Direction--Im not explaining this
		end

	end

	return MovingDirection
end

WorldMovingDirection.lua (1.6 KB)

13 Likes

how would i reverse this so if i had the movetopoint i could find the move direction?

Move direction is a property of humanoid, so you will always have the move direction.

This is amazing, is there any way to convert it into local space though?

1 Like