finding "facing direction" of a node.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By quizzcode

Hey there,
I’m working on a 2D Tower Defense with a top down view.
I have 4 different sprite for 4 different movement N.S.W.E.
I know how to set the animation and change them for the played, depending on what input is pressed.

I want to apply 4 direction to the enemies who’s path is defined by get_simple_path.
Is there a function that return me a vector 2 that i can identify as “going left” “going right” ?

Without the “input” from a key i have no clue how to do it.
Thx !

1 Like
:bust_in_silhouette: Reply From: Zylann

For a node that moves by repeatedly setting their position (such that velocity isn’t actually known, like it would for KinematicBody2D or RigidBody2D), you can determine the direction an enemy is going by comparing its current position and its position from the last frame.

var _position_last_frame := Vector2()
var _cardinal_direction = 0

func _physics_process(delta):
	# Get motion vector between previous and current position
	var motion = position - _position_last_frame

	# If the node actually moved, we'll recompute its direction.
	# If it didn't, we'll just the last known one.
	if motion.length() > 0.0001:
		# Now if you want a value between N.S.W.E,
		# you can use the angle of the motion.
		# I came up with this formula last time I needed it:
		_cardinal_direction = int(4.0 * (motion.rotated(PI / 4.0).angle() + PI) / TAU)

	# And now you have it!
	# You can even use it with an array since it's like an index
	match _cardinal_direction:
		0:
			print("West")
		1:
			print("North")
		2:
			print("East")
		3:
			print("South")

	# Remember our current position for next frame
	_position_last_frame = position

I used a fancy formula here but if you just need the motion vector, you can also work out something that suits you, by checking motion.x and motion.y.

darn ! I’m in 2d.
This is for a kinematic2d node.
Would you mind reviewing your answer for 2d ?

I’m looking at stepify() but that method isn’t part of the kinematicbdy2d class sadly.

quizzcode | 2020-05-11 20:11

stepify is a global function, it can be used anywhere.

Zylann | 2020-05-11 20:12

Answer updated for 2D. I guess stepify can also work the same way with angles, though you need to make sure a small offset is added to even out the “range” of each direction, see visualisation I made here (for 8 directions but the concept is the same with 4): Add diagonal constants to Vector2() like UP_LEFT · Issue #566 · godotengine/godot-proposals · GitHub

Zylann | 2020-05-11 20:16

thx ! I will give it a shot now !
I mentioned MOTION + previous/new frame position on godot discord and it looks like everyone agreed to be the best solution.

Tho, i will have 100-500 monsters at once on the map.
Which one of the methods between stopify and motion is lighter regarding CPU consumption in your opinion ?

quizzcode | 2020-05-11 20:18

are you confident truncating the direction is the right thing, as opposed to rounding it?

quizzcode | 2020-05-11 20:28

Can you post your stepify? Chances are it might be slightly faster because it moves a few of the operations from my formula to engine code.

Zylann | 2020-05-11 20:29

I honestly didnt get a chance to make it work as kinematicbody doesn’t work with stopify…

quizzcode | 2020-05-11 20:30

This solved my problem to the letter. Thank you very much for posting!

kgbemployee | 2022-12-03 19:48

this formula is a miracle sent from god and you are jesus kind sir