Aerial Attack on Godot

I'm new to Godot, and I'm making a personal project, a 2D platformer, a clone of Ninja Gaiden (1988), but I'm having trouble getting the aerial attack to work. The Player script is the following:

extends KinematicBody2D

onready var Animated_player = $AnimatedSprite
onready var Sword = $Sword/CollisionShape2D

export var Acceleration = 512
export var Max_speed = 64
export var Friction = 0.25
export var Air_resistance = 0.02
export var Gravity = 200
export var Jump_force = 100

var Is_attacking = false
var motion = Vector2.ZERO

func _physics_process(delta):
    var x_input = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
    
    if Input.is_action_just_pressed("Attack"):
            Animated_player.play("Attack")
            Sword.disabled = false
            Is_attacking = true
            motion.x = 0


    if x_input != 0 and Is_attacking == false:
        Sword.disabled = true
        Animated_player.play("Walk")
        motion.x += x_input * Acceleration * delta
        motion.x = clamp(motion.x, -Max_speed, Max_speed )
        Animated_player.flip_h = motion.x < 0 
        
    else:
        if Is_attacking == false:
            Sword.disabled = true
            Animated_player.play("Idle")
            motion.x = lerp(motion.x, 0, Friction * delta)
    motion.y += Gravity * delta

    if test_move(transform, Vector2.DOWN):
        if x_input == 0:
            motion.x = lerp(motion.x, 0, Friction)
            
        if Input.is_action_just_pressed("Jump"):
            motion.y = -Jump_force

    else:
        if Input.is_action_just_pressed("Attack"):
            Sword.disabled = false
            motion.x = lerp(motion.x, 0, Air_resistance)
            Animated_player.play("Jump_Attack")
            motion.x = lerp(motion.x, 0, Air_resistance)

        if Is_attacking == false:
            Sword.disabled = true
            if motion.y < 0:
                Animated_player.play("Jump")
            if motion.y > 0:
                Animated_player.play("Fall")
            if Input.is_action_just_released("Jump") and motion.y < -Jump_force/2:
                motion.y = -Jump_force/2
            if x_input == 0:
                motion.x = lerp(motion.x, 0, Air_resistance)

    move_and_slide(motion)

    motion = move_and_slide(motion, Vector2.UP)

func _on_AnimatedSprite_animation_finished():
    if Animated_player.animation == "Attack" or Animated_player.animation == "Jump_Attack": 
        Is_attacking = false
        Sword.disabled = true

The Jump_Attack animation plays right, but I want the "Air resistance" to be true while you attack on the air, but if you attack on the ground I want motion.x to be zero.

but whenever I make motion.x = 0 inside the if Input.is_action_just_pressed: it stops your movement on the air as well.

How can I solve this?

Upvotes: 0

Views: 471

Answers (1)

JayBert
JayBert

Reputation: 36

When making any kind of platformer, a good thing to add to the movement script is a "grounded" variable, which determine if the player is on the ground or not. you can do so with something like this (when using is on floor, make sure you always have a gravity applied to your player, and set it after the move_and_slide()):

var grounded = false

func process(_delta):
    #move_and_slide(...)
    grounded = is_on_floor()

then in your if that check if the attack key is pressed, if the player is grounded, you cant set your motion.x to 0 and if not, don't.

As you mentioned in your comment, now when you land during an attack, the idle or walk animation doesn't play right away because you don't check if the player is grounded when you set your animation to walk or idle and that your condition for your walk and idle animation check if the player is attacking and the only time your variable Is_Attacking is set to false is when the animation ends. here is what I would try,

in your physics_process function:

physics_process(delta):
    var x_input = Input.get_action_strength("ui_right") -Input.get_action_strength("ui_left")

    if Input.is_action_just_pressed("Attack"):
            Animated_player.play("Attack")
            Sword.disabled = false
            Is_attacking = true
            

    if Is_Attacking and grounded:
        motion.x = 0

    #the rest of your code
    move_and_slide(...)
    grounded = is_on_floor()

So you check if the player is grounded and attacking then you set the motion to 0. the player should be able to move and attack in the air, but if he touch the ground while attacking, motion is set to 0, and when the animation end, the player can walk or idle. this solve the animation issue and the "gliding".

Now if you want to just cancel the attack animation when landing so the player can walk or idle as he touch the ground, you can add a variable "Is_air_attacking" and do:

physics_process(delta): var x_input = Input.get_action_strength("ui_right") -Input.get_action_strength("ui_left")

if Input.is_action_just_pressed("Attack"):
        Animated_player.play("Attack")
        Sword.disabled = false
        Is_attacking = true
        if !grounded:
            Is_air_attacking = true


if Is_Attacking and grounded:
    if Is_air_attacking:
        Is_air_attacking = false
        Is_Attacking = false
        Sword.disabled = false
    else:            
        motion.x = 0

#the rest of your code
move_and_slide(...)
grounded = is_on_floor()

    

Upvotes: 0

Related Questions