8-way movement in an isometric 2d game with the AnimatedSprite node

EricEric Posts: 5Member

Hello there, i am a beginner in game development and right now i am learning the basics.
Because i love the isometric view in games i am using the isometric dungeon tileset vom kenny.nl to learn on isometric game design in Godot and i wanted to animate the player figure in the way that the player can move in all of the 8 directions.
So i have prepared the animations with the animation editor but only 4 of the 8 run animations are working properly in the code. The same goes for the idle animation (which basically is only one frame).
I was searching in the Godot documentation and on YouTube to find a solution but i couldn't find any.
The animations which are working fine are the left, right, up and down run animations and also the idle animation.
This is the code of the movement which is working:

extends KinematicBody2D


export (int) var speed = 200

var velocity = Vector2()


func get_input():
#   get_global_mouse_position()
    velocity = Vector2()

    if Input.is_action_pressed("right"):
        velocity.x += 1
        $AnimatedSprite.play("run_right")
    if Input.is_action_just_released("right"):
        $AnimatedSprite.play("idle_right")

    if Input.is_action_pressed("left"):
        velocity.x -= 1
        $AnimatedSprite.play("run_left")
    if Input.is_action_just_released("left"):
        $AnimatedSprite.play("idle_left")

    if Input.is_action_pressed("down"):
        velocity.y += 1
        $AnimatedSprite.play("run_down")
    if Input.is_action_just_released("down"):
        $AnimatedSprite.play("idle_down")

    if Input.is_action_pressed("up"):
        velocity.y -= 1
        $AnimatedSprite.play("run_up")
    if Input.is_action_just_released("up"):
        $AnimatedSprite.play("idle_up")


    velocity = velocity.normalized() * speed


func _physics_process(delta):
    get_input()
    velocity = move_and_slide(velocity)

And i was trying this snippet here for the diagonal directions but it's not working:

if Input.is_action_pressed("right") and Input.is_action_pressed("down"):
            $AnimatedSprite.play("run_d_right_down")
        if Input.is_action_just_released("right") or Input.is_action_just_released("down"):
            $AnimatedSprite.play("idle_d_right_down")

Does someone maybe knows what i am doing wrong? I thought i could maybe solve the problem by adding a key-combination of s + d in the input map but it seems that setting up two keys for one command does only work with combinations like alt + s and so on.

I hope it is ok if i am asking a second question towards movement additionally. :)
My idea for the movement of the player charakter is a combination of keyboard and mouse controls. I basically would like to use the mouse for the direction the playersprite is facing and on which he is performing it's actions. So let's say the player character can face an enemy because the player is moving the mouse cursor in the direction of the enemy. At the same time the player should also be able to move forward or backwards or sideway.
I was looking today a few hours for documentations and YouTube material and so on to achieve this kind of movement but haven't found any. Maybe i was overlooking thoseparts of the documentation? I was also playing around with the "get_global_mouse_position" method but that was looking quite strange.
If someone could help me out that would be cool. :)
And please excuse my clumsy english, i am not a native speaker.

Answers

  • TwistedTwiglegTwistedTwigleg Posts: 2,127Admin

    I only glanced through the post, but I think the post I made on this thread may help. It has code showing how a 8-direction animation system could work, which may be useful to use as a reference.

  • EricEric Posts: 5Member

    Thank you, i will try it out. :)

  • EricEric Posts: 5Member
    edited March 26

    I was trying your example out. I was replacing all z axis related stuff for i thought there is no z axis in a 2D game.
    Now my figure can run in six directions. It's interesting, the animation for up and down movement is not played. And the movement feels a bit strange because the figure seems now to be sliding. But the figure can now move in six of the eight directions fluently.
    This is the code:

    extends AnimatedSprite
    
    var moving_anim_name = "Run_Up";
    var idle_anim_name = "Idle_Up";
    var velocity = Vector2();
    var move_speed = 2;
    
    # variables to track which input keys have been pressed:
    var input_vector = Vector2.ZERO;
    var last_directional_input = Vector2.ZERO;  
    
    
    
    
    #func _ready():
    #   play("Idle_Up");
    
    func _process(delta):
    
        if (Input.is_action_pressed("right")):
            velocity.x += move_speed;
            input_vector.x = 1
        elif (Input.is_action_pressed("left")):
            velocity.x -= move_speed;
            input_vector.x = -1
        else:
            velocity.x = 0;
            input_vector.x = 0
    
        if (Input.is_action_pressed("up")):
            velocity.y -= move_speed;
            input_vector.y = -1
        elif (Input.is_action_pressed("down")):
            velocity.y += move_speed;
            input_vector.y = 1
        else:
            velocity.y = 0;
            input_vector.y = 0
    
        global_translate(velocity * delta)
    
        # If the input_vector is NOT zero, then we want to store the direction
        # for the idle animation.
    
        if (input_vector != Vector2.ZERO):
            last_directional_input  = input_vector
    
        # last_directional_input should always contain the direction the player
        # is moving towards if the player is moving, or the last direction the player
        # moved towards if the player is no longer moving.
        # Now we can replace input_vector with last_directional_input for
        # animations.
    
        var h_vel = velocity;
        h_vel.y = 0;
        # Walking animations below:
        if (h_vel.length() > 0):
            if (last_directional_input .y <= -1):
                if (last_directional_input .x <= -1):
                    _change_sprite_animation("Run_UL")
                elif (last_directional_input .x >= 1):
                    _change_sprite_animation("Run_UR")
                else:
                    _change_sprite_animation("Run_Up")
            elif (last_directional_input .y >= 1):
                if (last_directional_input .x <= -1):
                    _change_sprite_animation("Run_DL")
                elif (last_directional_input .x >= 1):
                    _change_sprite_animation("Run_DR")
                else:
                    _change_sprite_animation("Run_Down")
            else:
                if (last_directional_input .x <= -1):
                    _change_sprite_animation("Run_Left")
                elif (last_directional_input .x >= 1):
                    _change_sprite_animation("Run_Right")
        # Idle animations below:
        else:
            if (last_directional_input .y <= -1):
                if (last_directional_input .x <= -1):
                    _change_sprite_animation("Idle_UL")
                elif (last_directional_input .x >= 1):
                    _change_sprite_animation("Idle_UR")
                else:
                    _change_sprite_animation("Idle_Up")
            elif (last_directional_input .y >= 1):
                if (last_directional_input .x <= -1):
                    _change_sprite_animation("Idle_DL")
                elif (last_directional_input .x >= 1):
                    _change_sprite_animation("Idle_DR")
                else:
                    _change_sprite_animation("Idle_Down")
            else:
                if (last_directional_input .x <= -1):
                    _change_sprite_animation("Idle_Left")
                elif (last_directional_input .x >= 1):
                    _change_sprite_animation("Idle_Right")
    
    # A simple helper function for changing animations
    func _change_sprite_animation(new_animation_name):
        if (animation != new_animation_name):
            play(new_animation_name);`
    

    I am a bit confused that this code has been writen inside the AnimatedSprite node and not in the KindematicBody2D Node with referencing. At least the YouTube Tutorial i was watching has used the KinematicBody2D with referencing. But that was also a normal platformer example which has been programmed.

    If i might ask this only for me for understanding: What kind of problems does my initial approach is making to the engine? I am just curious. For the only problem seems to be, that the diagonal movement is not shown completly. For example the player figure is heading in that diagonal direction if i am hiting (lets say) "w" and "d" but not the animation itself. Only the first picture of the diagonal animation is played. So the figure is moving its body to the up-right (or forward-east) direction but no movement is there.

  • TwistedTwiglegTwistedTwigleg Posts: 2,127Admin
    edited March 27

    @Eric said:
    I was trying your example out. I was replacing all z axis related stuff for i thought there is no z axis in a 2D game.
    Now my figure can run in six directions. It's interesting, the animation for up and down movement is not played. And the movement feels a bit strange because the figure seems now to be sliding. But the figure can now move in six of the eight directions fluently.
    This is the code:
    ...

    Ah, my bad. I didn't see you were looking for a 2D solution. The post I linked to was for a project in 3D, which is why there is an additional Z axis.

    It is strange that the animation for up and down is not playing. I'm guessing something is not being set or reset correctly. I'll take a look through the code posted and see if I can spot what is causing the issue.

    Edit: Maybe try printing last_direction_input when walking up or down and see what the results are? Looking at the code, I do not see anything amiss that would be causing it not to be working.

    I am a bit confused that this code has been writen inside the AnimatedSprite node and not in the KindematicBody2D Node with referencing. At least the YouTube Tutorial i was watching has used the KinematicBody2D with referencing. But that was also a normal platformer example which has been programmed.

    The user I was helping in the linked post was using an AnimatedSprite3D node instead of a KinematicBody3D node when I wrote the example code, which is why it extends the AnimatedSprite. You can change it to a KinematicBody2D node if you want, you'll just need to change the _change_sprite_animation.

    For example, if you are using a KinematicBody2D node with a child AnimatedSprite node called "AnimatedSprite", then you'd just need to change extends AnimatedSprite to extends KinematicBody2D and then change _change_sprite_animation to the following:

    # A simple helper function for changing animations
    var animated_sprite_node = null
    func _change_sprite_animation(new_animation_name):
        if (animated_sprite_node == null):
            animated_sprite_node = get_node("AnimatedSprite")
    
        if (animated_sprite_node .animation != new_animation_name):
            animated_sprite_node .play(new_animation_name);
    

    If i might ask this only for me for understanding: What kind of problems does my initial approach is making to the engine? I am just curious. For the only problem seems to be, that the diagonal movement is not shown completly. For example the player figure is heading in that diagonal direction if i am hiting (lets say) "w" and "d" but not the animation itself. Only the first picture of the diagonal animation is played. So the figure is moving its body to the up-right (or forward-east) direction but no movement is there.

    The issue your initial code was having, if I had to guess, is probably due to the execution order of the if statements. You'd need to rearrange your if statements so the flow acts as you'd expect, where directional movements are discovered first, and then movements in a single direction.

    For example, something like this:

    # just doing up directions in this example
    var is_up_pressed = Input.is_action_pressed("up")
    var is_left_pressed = Input.is_action_pressed("left")
    var is_right_pressed = Input.is_action_pressed("right")
    
    if is_up_pressed and is_left_pressed:
        print ("Up left pressed!")
    if is_up_pressed and is_right_pressed:
        print ("Up right pressed!")
    if is_up_pressed:
        print ("Up pressed!")
    

    will print both Up pressed and Up left pressed when you press up and left. Instead, you will likely want to use if and elif statements, in an order like this:

    # just doing up directions in this example
    var is_up_pressed = Input.is_action_pressed("up")
    var is_left_pressed = Input.is_action_pressed("left")
    var is_right_pressed = Input.is_action_pressed("right")
    
    if is_up_pressed:
        if is_right_pressed:
            print ("Up right pressed!")
        elif is_left_pressed:
            print ("Up left pressed!")
        else:
            print ("Up pressed!")
    

    That way, you can narrow down which key press you are getting. I think the issue with your initial code was that movement in a single direction was overriding the diagonal movement, much like how Up pressed was also being printed when up left was pressed.

    That said, I am just guessing based on the code, so please take this with a grain of salt. I think that is what is happening, but I haven't tried executing the code and am writing this off memory.

    Regardless, hopefully the explanation helps a bit!

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Emoji
Image
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file