Aerial Attack on Godot - 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?

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()

Related

Godot Dash Function

So, the code I have for a dash function is not working correctly even though im positive the logic is correct. I suspected the problem was with the variable isdashing so I printed out the value for it and comes back false no matter what I do. Can anyone tell me what im doing wrong?
extends KinematicBody2D
export(int) var Jump_Height = -100
export(int) var Jump_Realese = -60
export(int) var gravity = 4
var velocity = Vector2.ZERO
var move_speed = 50
#Jump Stuff
var max_jump = 2
var jump_count = 0
# Dash Stuff
var dash_direction = Vector2(1,0)
var dashable = false
var isdashing = false
# Movement
func _physics_process(delta):
dash()
gravity_control()
if Input.is_action_pressed("ui_right"):
velocity.x = move_speed
elif Input.is_action_pressed("ui_left"):
velocity.x = -move_speed
else:
velocity.x = 0
if is_on_floor() and jump_count != 0:
jump_count = 0
if jump_count<max_jump:
if Input.is_action_just_pressed("ui_up"):
velocity.y = Jump_Height
jump_count += 1
else:
if Input.is_action_just_released("ui_up") and velocity.y < Jump_Realese:
velocity.y = Jump_Realese
velocity = move_and_slide(velocity, Vector2.UP)
func dash():
if is_on_floor():
dashable = true
if Input.is_action_pressed("ui_left"):
dash_direction = Vector2(-1,0)
if Input.is_action_pressed("ui_right"):
dash_direction = Vector2(1,0)
if Input.is_action_just_pressed("ui_Dash") and dashable:
velocity = dash_direction.normalized() * 7000
dashable = false
isdashing = true
yield(get_tree().create_timer(0.2), "timeout")
isdashing = false
It's likely that Input.is_action_just_pressed("ui_Dash") is false because dash() is being called in the physics_process function which doesn't run every frame (it runs 60 times a second).
What currently happens is -
During a game frame, the user presses the dash button. At this point Input.is_action_just_pressed("ui_Dash") is true but nothing has checked it.
A frame or two (or more) later, the dash function is called in the physics_process. This polls if the dash button was just pressed - but now it's false because it was "just pressed" a few frames ago, not on this frame.
The only way your current logic works is if the dash button was pressed in the EXACT frame that the physics_process runs.
You can get around this by using Input.is_action_pressed("ui_Dash") to capture the button press, setting a flag to prevent it being captured on the next physics frame and then enabling it again sometime later. E.g.
var can_dash: boolean = true
func dash():
if is_on_floor():
dashable = true
if Input.is_action_pressed("ui_left"):
dash_direction = Vector2(-1,0)
if Input.is_action_pressed("ui_right"):
dash_direction = Vector2(1,0)
if can_dash and Input.is_action_pressed("ui_Dash") and dashable:
can_dash = false;
velocity = dash_direction.normalized() * 7000
dashable = false
isdashing = true
yield(get_tree().create_timer(0.2), "timeout")
isdashing = false
can_dash = true
You are resetting your variables (especially velocity) before calling move_and_slide().
Solution: Call dash() immediately before calling move_and_slide().
This is the reset I'm referring to:
if Input.is_action_pressed("ui_right"):
velocity.x = move_speed
elif Input.is_action_pressed("ui_left"):
velocity.x = -move_speed
else:
velocity.x = 0

Animation bug. Using godot game engine

I am working on a game and for some reason when I try to call the hit_check() function it won't animate the sprite. all of the other animations have worked perfectly which is why I'm confused.
Heres my script:
extends KinematicBody2D
var motion = Vector2(0,0)
const SPEED = 130
const GRAVITY = 15
const UP = Vector2(0,-1)
const JUMP_SPEED = 350
func _physics_process(delta):
apply_gravity()
hit_check()
jump_check()
move_check()
move_and_slide(motion, UP)
func apply_gravity():
if not is_on_floor():
motion.y += GRAVITY
else:
motion.y = 0
func jump_check():
if Input.is_action_pressed("jump") and is_on_floor():
motion.y -= JUMP_SPEED
func move_check():
if Input.is_action_pressed('left'):
$PlayerAnimation.flip_h = true
$PlayerAnimation.play("walk")
motion.x = -SPEED
elif Input.is_action_pressed('right'):
$PlayerAnimation.flip_h = false
$PlayerAnimation.play("walk")
motion.x = SPEED
else:
motion.x = 0
$PlayerAnimation.play("idle")
func hit_check():
if Input.is_action_pressed("hit"):
$PlayerAnimation.play("hit")
jump_check and move_check functions are called after hit_check function, and move_check function always overrides the current animation of the node because there is an animation specified in both if and else blocks.

i was making a Godot platformer with the help of a video on Youtube I've done everything same as him but my character refuses to move left

I'm trying to make a 2d platformer in godot with help from one of the the videos. video link: https://www.youtube.com/watch?v=PG0tfoPraE4. I have very little experience working with Godot.
I'm stuck and am not sure what to do, I've tried looking at some more videos as a last resort but all of them use another way of movement.
Here is the code
GDSCRIPT
extends KinematicBody2D
const MOVESPEED = 70
const JUMPFORCE = -200
const GRAVITY = 600
var motion = Vector2()
func _physics_process(delta):
if is_on_floor():
if Input.is_action_just_pressed("ui_up"):
motion.y = JUMPFORCE
if Input.is_action_pressed("ui_left"):
motion.x = -MOVESPEED
$Sprite.flip_h = true
$AnimationPlayer.play("walk")
if Input.is_action_pressed("ui_right"):
motion.x = MOVESPEED
$Sprite.flip_h = false
$AnimationPlayer.play("walk")
else:
motion.x = 0
$AnimationPlayer.stop()
motion.y += GRAVITY * delta
motion = move_and_slide(motion, Vector2(0,-1))
Your code path is falling into the else clause of the right movement. So preventing it to move.
Just add and else to the right if, like:
if Input.is_action_pressed("ui_left"):
motion.x = -MOVESPEED
$Sprite.flip_h = true
$AnimationPlayer.play("walk")
elif Input.is_action_pressed("ui_right"):
motion.x = MOVESPEED
$Sprite.flip_h = false
$AnimationPlayer.play("walk")
else:
motion.x = 0
$AnimationPlayer.stop()

How can I make the player and enemies fall to the ground when they die?

I'm making my first game in Godot.
No matter what I try, if the player/enemies die while in the air, they stay there. I want them to fall to the ground when they die. Help?
While at it if you have any pointers based on what you can see from my code, I'll really appreciate it. Especially when it comes to player movement and such. Currently, very few actions feel smooth; a lot of stuff feels rather rigid and wonky (jumping, falling from edges, and the enemy's collision shape somehow displaces itself as the enemy moves).
PLAYER CODE:
var motion = Vector2 ()
var is_in_attack = false
var fireball_power = 1
var is_dead = false
var is_jumping = false
func _physics_process(delta):
if is_dead == false:
motion.y += GRAVITY
var friction = false
if Input.is_action_pressed("ui_right"):
if is_in_attack == false || is_on_floor() == false:
motion.x = min(motion.x+ACCELERATION, MAX_SPEED)
if is_in_attack == false:
$Sprite.flip_h = false
$Sprite.play("run")
if sign($FireballPosition2D.position.x) == -1:
$FireballPosition2D.position.x *= -1
if sign($FireballPosition2D2.position.x) == -1:
$FireballPosition2D2.position.x *= -1
if sign($ArrowPosition2D.position.x) == -1:
$ArrowPosition2D.position.x *= -1
elif Input.is_action_pressed("ui_left"):
if is_in_attack == false || is_on_floor() == false:
motion.x = max(motion.x-ACCELERATION, -MAX_SPEED)
if is_in_attack == false:
$Sprite.flip_h = true
$Sprite.play("run")
if sign($FireballPosition2D.position.x) == 1:
$FireballPosition2D.position.x *= -1
if sign($FireballPosition2D2.position.x) == 1:
$FireballPosition2D2.position.x *= -1
if sign($ArrowPosition2D.position.x) == 1:
$ArrowPosition2D.position.x *= -1
else:
if is_in_attack == false:
$Sprite.play("idle")
friction = true
var snap = Vector2.DOWN *32 if !is_jumping else Vector2.ZERO
motion = move_and_slide_with_snap(motion,snap, UP)
pass
if get_slide_count() > 0:
for i in range(get_slide_count()):
if "Enemy" in get_slide_collision(i).collider.name:
dead()
for i in get_slide_count():
var collision = get_slide_collision(i)
if collision.collider.has_method("collide_with"):
collision.collider.collide_with(collision, self)
func dead():
is_dead = true
motion = Vector2(0,0)
$CollisionShape2D.set_deferred("disabled", true)
$Sprite.play("dead")
$Timer.start()
PlayerData.deaths += 1
func _on_attackarea_body_entered(body):
if "Enemy" in body.name:
body.dead(1)
ENEMY CODE:
const UP = Vector2 (0, -1)
const GRAVITY = 20
const ACCELERATION = 50
const JUMP_HEIGHT = -500
var motion = Vector2 ()
var direction = 1
var is_dead = false
export(int) var speed = 50
export(int) var hp = 1
export(Vector2) var size = Vector2(1, 1)
export var score: = 100
func _ready():
scale = size
pass
func dead(damage):
hp = hp -damage
if hp <=0:
is_dead = true
motion = Vector2(0,0)
$AnimatedSprite.play("dead")
$CollisionShape2D.set_deferred("disabled", true)
$Timer.start()
PlayerData.score += score
#calling the screenshake for large enemies
if scale > Vector2(1.6, 1.6):
get_parent().get_node("ScreenShake").screen_shake(1, 10, 100)
func _physics_process(delta):
if is_dead == false:
motion.x = speed * direction
if direction == 1:
$AnimatedSprite.flip_h = false
$CollisionShape2D.position.x = 1
else:
$AnimatedSprite.flip_h = true
$CollisionShape2D.position.x = -1
$AnimatedSprite.play("walk")
motion.y += GRAVITY
motion = move_and_slide(motion, UP)
if is_on_wall():
direction = direction * -1
if get_slide_count() > 0:
for i in range (get_slide_count()):
if "Player" in get_slide_collision(i).collider.name:
get_slide_collision(i).collider.dead()
Since it worked, I will add it as an official answer:
you only move the character in your physics_process as long as he is still alive:
func _physics_process(delta):
if is_dead == false:
# all the gravity code is in here.
Add an else statement for 'if is_dead == false' which moves the node on y direction as long as its not on the ground. Something like that should work:
func _physics_process(delta):
if is_dead == false:
# your code
else:
if not is_on_floor():
motion.y += GRAVITY
motion = move_and_slide(motion, UP)

How do I write a code that controls jumps, and creates a double jump action'?

# changed switch statement setup by creating a new variable and using "." operator
# removed extra delta in move_and_slide function
# left off attempting to add gravity to the game
# 2/26/2019
# removed FSM and will replace it with tutorial video code, for sake of completion
extends Node2D
const FLOOR = Vector2(0,-1)
const GRAVITY = 5
const DESCEND = 0.6
var speed = 100
var jump_height = -250
var motion = Vector2()
var jump_count = 0
var currentState = PlayerStates.STATE_RUNNING
var grounded = false
enum PlayerStates {STATE_RUNNING, STATE_JUMPING, STATE_DOUBLE_JUMPING, STATE_GLIDING}
func _ready():
var currentState = PlayerStates.STATE_RUNNING
pass
func jump():
motion.y = jump_height
func glide():
if motion.y < 500:
motion.y += DESCEND
func _process(delta):
var jump_pressed = Input.is_action_pressed('jump')
var glide_pressed = Input.is_action_pressed('glide')
* the code below is where I attempted to count the jumps in order to keep them from surpassing two jumps. My goal is to create a double
jump and so I used the less than operator to control that number*
if jump_pressed:
if jump_count < 2:
jump_count += 1
jump()
grounded = false <-- I had to copy paste this code again, below, so I don't get an error in my question.
if jump_pressed:
if jump_count < 2:
jump_count += 1
jump()
grounded = false
if grounded == false:
if glide_pressed:
glide()
motion.x = speed
motion.y += GRAVITY
motion = move_and_slide(motion, FLOOR)
if is_on_floor():
grounded = true
jump_count = 0
else:
grounded = false
First of all, I think you need to use a KinematicBody2D and perform your logic in _physics_process if you would like to use move_and_slide, other than that, your code was almost working:
extends KinematicBody2D
const FLOOR = Vector2(0,-1)
const GRAVITY = 3000
const DESCEND = 0.6
var speed = 100
var jump_height = 250
var motion = Vector2()
var jump_count = 0
func jump():
motion.y = -jump_height
func glide():
if motion.y < 500:
motion.y += DESCEND
func _physics_process(delta):
var jump_pressed = Input.is_action_pressed('jump')
var glide_pressed = Input.is_action_pressed('glide')
motion.y += delta * GRAVITY
var target_speed = Vector2(speed, motion.y)
if is_on_floor():
jump_count = 0
if glide_pressed:
glide()
if jump_pressed and jump_count < 2:
jump_count += 1
jump()
motion = lerp(motion, target_speed, 0.1)
motion = move_and_slide(motion, FLOOR)
You also need to change the node type to KinematicBody2D in the Godot editor (right click on the node and then on change type).

Resources