Wednesday, March 27, 2024

Animating the sprite part3

 Yet again another entry for animated sprites, this time to make an attack action.

We'll be working upon the previous part 1 and part 2. Assuming you have your attack action key framed already, we can go and start creating the state machine and set up the states.

- To do this, we need to create a few more variables in our script:

```
extends KinematicBody2D

const ACCELERATION = 500
const MAX_SPEED = 80
const FRICTION = 500

enum {
    MOVE,
    ROLL,
    ATTACK
}
var state = MOVE
var velocity = Vector2.ZERO

onready var animationPlayer = $AnimationPlayer
onready var animationTree = $AnimationTree
onready var animationState = animationTree.get("parameters/playback")
```

- With them, we can update our functions to select the state it's in each time. Now we update the rest of the code
 
```
func _ready():
    animationTree.active = true

func _physics_process(delta):
    match state:
        MOVE:
            move_state(delta)
        ROLL:
            pass
        ATTACK:
            attack_state(delta)
    
func move_state(delta):
    var input_vector = Vector2.ZERO
    input_vector.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
    input_vector.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
    input_vector = input_vector.normalized()

    if input_vector != Vector2.ZERO:
        animationTree.set("parameters/Idle/blend_position", input_vector)
        animationTree.set("parameters/Run/blend_position", input_vector)
        animationState.travel("Run")
        velocity = velocity.move_toward(input_vector * MAX_SPEED, ACCELERATION * delta)
    else:
        animationState.travel("Idle")
        velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)
    
    velocity = move_and_slide(velocity)
    
    if Input.is_action_just_pressed("attack"):
        state = ATTACK

func attack_state(delta):
    animationPlayer.play("AttackDown")
```


- However we don't have our BlendingSpace state and the attack goes in loop. So, it's time to add a new blendSpace2D:

- Set transitions from/to Idle, and add your vertex for the attack node

- Now, it gets to do one attack and gets blocked because it doesn't know what to do next. To fix that, we are going to add

add a track (a function) in our animationPlayer for each attack, we'll do one attack here as example

- Select "call method track", and select your player node in the pop-up

- Create a function for the attack finishing in your player script:
```
func attack_animation_finished():
    state = MOVE
```


- Go back to your animation animationPlayer and add an animation key in the newly appeared track.

- You want to select your created function `attack_animation_finished`

- Do the same for all your attack animations. Before running the game, your code for the player script should currently look like this:
```
extends KinematicBody2D

const ACCELERATION = 500
const MAX_SPEED = 80
const FRICTION = 500

enum {
    MOVE,
    ROLL,
    ATTACK
}
var state = MOVE
var velocity = Vector2.ZERO

onready var animationPlayer = $AnimationPlayer
onready var animationTree = $AnimationTree
onready var animationState = animationTree.get("parameters/playback")

func _ready():
    animationTree.active = true

func _physics_process(delta):
    match state:
        MOVE:
            move_state(delta)
        ROLL:
            pass
        ATTACK:
            attack_state(delta)
    
func move_state(delta):
    var input_vector = Vector2.ZERO
    input_vector.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
    input_vector.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
    input_vector = input_vector.normalized()

    if input_vector != Vector2.ZERO:
        animationTree.set("parameters/Idle/blend_position", input_vector)
        animationTree.set("parameters/Run/blend_position", input_vector)
        animationTree.set("parameters/Attack/blend_position", input_vector)
        animationState.travel("Run")
        velocity = velocity.move_toward(input_vector * MAX_SPEED, ACCELERATION * delta)
    else:
        animationState.travel("Idle")
        velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)
    
    velocity = move_and_slide(velocity)
    
    if Input.is_action_just_pressed("attack"):
        state = ATTACK

func attack_state(delta):
    animationState.travel("Attack")

func attack_animation_finished():
    state = MOVE
```


If you followed this entry carefully, your character should have animations for moving around and attacking.
The next step should be adding hitboxes and hurtboxes, however, since this has become a bit of a big entry, will do those in the next entry. (Meanwhile, you can add a roll action following the attack example)

No comments:

Post a Comment