Calculating what cardinal direction the player is looking in?

hi! i’m trying to make a basic compass display for my first person 3D game, but i can’t quite figure out how to get what cardinal direction they’re looking in. i know it’s something to do with the player’s rotation, but i both don’t exactly know how to get that and have no clue how to do the math to turn that into a cardinal direction.

i can absolutely figure out the player rotation part on my own eventually, but i’m horrible at math. does anyone know what i’d do math wise here?

Just to clarify you want to end up with “North” or “South-East” as text from the player’s direction?

In 2D it would be a process of converting the player’s rotation property to an array of directions, mathematically it means you need to convert the rotation from a range of 0-TAU to 0-8 with 8 representing each direction.

From 0-TAU we can divide by TAU to get a 0-1 range which is much more manageable unit/normal range, we can multiply this by 8 to get our desired range.

var index_range: int = rotation / TAU * 8

Then we use the index, in 2D our array assumes 0 is East since that’s the norm mathematically, 0 rotation faces right then continues clockwise.

const DIRECTIONS: Array[String] = ["East", "South-East", "South", "South-West", "West", "North-West", "North", "North-East"]
var cardinal_direction := DIRECTIONS[index_range]

Now in 3D rotation.y may work depending on how you rotate your character. If zero doesn’t face East in your game then you can re-arrange the DIRECTIONS array.

this doesn’t seem to work in 3D :(!! it almost does, but west is never grabbed and east is about double as big as it should be, weirdly. i am just using the player’s rotation.y!

Double as big, what does that mean? Could you paste your code?

yeah, it’s noticeably bigger & with a separate label that shows the player’s current rotation it shows east to be double as big (probably why west is gone too?)

this is in my ui’s process function:

	var index_range: int = main_node.get_node("Player").rotation.y / TAU * 8
	const DIRECTIONS = ["East", "South-East", "South", "South-West", "West", "North-West", "North", "North-East"]
	var cardinal_direction = DIRECTIONS[index_range]
	
	get_node("TestLabel").text = cardinal_direction

If by double as big you mean it shows East more often than you believe it should, maybe rounding through roundi would help? By default converting from a float to int will truncate so 1.8 would turn into 1.0 but with rounding it would result in 2.0

var index_range: int = roundi(main_node.get_node("Player").rotation.y / TAU * 8)

You can use the player forward direction (-GlobalBasis.Z) and do the dot product against a global north direction vector (0,0,1) or whatever direction you want “north” to be and also the dot product with an “east” vector, then depending on the dot products you’ll be able to figure out the direction the player is facing.

You might have to project the player forward direction onto a horizontal plane and normalize it before doing the dot products.

From a dot product you should get the arc cosine to get the original angle, and that may end up being the same as rotation.y but with an offset, i.e. maybe not facing East

But what if the character rotation has a pitch? Wouldn’t that mess things up if you use the rotation.y directly?
By projecting the forward vector onto a horizontal plane and normalizing it that would be prevented.

I would bet vector.y does not take into account other rotations. Though it’s uncommon to directly pitch or yaw a player (CharacterBody3D) so I’m not worried that’s going to be a problem for this scenario.

i’m really not sure what any of this means because i don’t know this level of math, but the character only has the rotation.y

maybe rounding through roundi would help? By default converting from a float to int will truncate so 1.8 would turn into 1.0 but with rounding it would result in 2.0

@gertkeno (sorry for the weird quote, seems like the discourse layout changes every day) this completely fixed it! west exists, east is fine, etc. the only problem now is it seems reversed (turning left from north sends me to north-east) but i know i can fix that by just rearranging the enums. thank you so much!