0 votes

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 getsimplepath.
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 !

in Engine by (184 points)
edited by

1 Answer

+1 vote
Best answer

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.

by (27,784 points)
selected by

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 ************** class sadly.

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

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): https://github.com/godotengine/godot-proposals/issues/566#issuecomment-596266660

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 ?

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

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.

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

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.