Home > Software design >  GODOT - Full Attack Animation Not Playing
GODOT - Full Attack Animation Not Playing

Time:12-26

I have this simple game i made in Even in the video sometimes it doesn't capture it.

This is my Character's Code:

extends KinematicBody2D

var _inputVec = Vector2.ZERO
var VELOCITY = Vector2.ZERO
var LAST_INPUT = Vector2.ZERO
const MAX_SPEED = 70
const ACCELERATION = 500
const FRICTION = 500

onready var animationPlayer = $AnimationPlayer

func _ready():
    print("game started!")

func _physics_process(delta):
    _inputVec.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
    _inputVec.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
    _inputVec = _inputVec.normalized()
    
    if _inputVec != Vector2.ZERO:
        if _inputVec.x > 0:
            animationPlayer.play("playerRunRight")
        elif _inputVec.y < 0:
            animationPlayer.play("playerRunUp")
        elif _inputVec.y > 0:
            animationPlayer.play("playerRunDown")
        else:
            animationPlayer.play("playerRunLeft")

        VELOCITY = VELOCITY.move_toward(_inputVec * MAX_SPEED, ACCELERATION * delta)
        LAST_INPUT = _inputVec
    else:
        VELOCITY = VELOCITY.move_toward(Vector2.ZERO, FRICTION * delta)

        if Input.is_action_just_pressed("ui_lmb"):
            if LAST_INPUT.x > 0:
                animationPlayer.play("playerAttackRight")
            elif LAST_INPUT.y < 0:
                animationPlayer.play("playerAttackUp")
            elif LAST_INPUT.y > 0:
                animationPlayer.play("playerAttackDown")
            else:
                animationPlayer.play("playerAttackLeft")
        else:
            if LAST_INPUT.x > 0:
                animationPlayer.play("playerIdleRight")
            elif LAST_INPUT.y < 0:
                animationPlayer.play("playerIdleUp")
            elif LAST_INPUT.y > 0:
                animationPlayer.play("playerIdleDown")
            else:
                animationPlayer.play("playerIdleLeft")

    VELOCITY = move_and_slide(VELOCITY)

Full Project is Available at my Github Repo

CodePudding user response:

Remember that _physics_process runs once per (physics) frame.

So, one frame you pressed the left mouse button, and this line got to execute:

                animationPlayer.play("playerAttackRight")

But next (physics) frame, you had not just pressed the left mouse button, so this conditional is false:

        if Input.is_action_just_pressed("ui_lmb"):

And then this line get to execute:

                animationPlayer.play("playerIdleRight")

As a result, you only see about one frame of the "playerAttackRight" animation.


You are going to need to keep track of the current state (running, attacking, idle). The rule is that you can change from running to idle immediately, but you can only change from attacking to idle, when the attack animation ends.

You can keep track of the current state with a variable, of course. You can take input and the value of the state of the variable to decide the new state. Then separately read the state variable and decide which animation to play. You may also want to set the state variable when some animations end.

And to do something when an animation ends, you can either resource to yield:

yield(animationPlayer, "animation_finished")

Which will have your code resume after it receives the "animation_finished" signal.

Or, otherwise you can connect to the "animation_finished" signal.

By the way, you can also queue animations:

animationPlayer.queue("name_of_some_animation")

While using AnimationPlayer like you do is OK. When it gets complex, there is another tool you should consider: AnimationTree.

Create an AnimationTree node, give it your animation player, and set the root to a new AnimationNodeStateMachine. There you can create your state machine, and configure if the transition between them is immediate or at the end.

Then, from code, you can get the state machine playback object, like this:

var state_machine = $AnimationTree.get("parameters/playback")

You can ask it what the current state is with:

var state:String = state_machine.get_current_node()

Which you can use as part of the decision of which state you want to go to. And then tell it you want it to go to a different state, like this:

state_machine.travel("name_of_some_state")

And using that it will respect the transitions you set, so you do not have to worry about it in code.


You can find more information about using AnimationTree at:

  • Related