2d metroidvania like code help new

Godot Version

godot 4.4.1

Question

so im having trouble with 2d slide animation and am trying to add a spin in between jump and fall animations. Also, i have crouch and slide but crouch lets me still move rather than being static and i try adding is_crouching to slide but it still seems to ignore it and slide whenever.

extends CharacterBody2D

@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D

const GRAVITY = 1000

enum State {Idle, Run, Jump, Crouch, Slide}

var current_state
var slide_timer := 0
var slide_timer_max := 1
var slide_duration = 1
var is_sliding
var has_spun = false
var is_crouching = false

func _ready():
current_state = State.Idle

func _physics_process(delta):
player_falling(delta)
player_idle(delta)
player_run(delta)
player_jump(delta)
player_slide(delta)

move_and_slide()

player_animations()

func player_falling(delta):
if !is_on_floor():
velocity.y += GRAVITY * delta

func player_idle(_delta):
if is_on_floor():
current_state = State.Idle
elif is_on_floor() and Input.is_action_pressed(“crouch_press”):
is_crouching = true
current_state = State.Crouch

func player_run(_delta):
var direction = Input.get_axis(“move_left”, “move_right”)

if direction:
	velocity.x = direction * 300
else:
	velocity.x = move_toward(velocity.x, 0, 300)

if direction != 0:
	current_state = State.Run
	animated_sprite_2d.flip_h = false if direction > 0 else true

func player_jump(_delta):
if Input.is_action_just_pressed(“jump_press”):
current_state = State.Jump
velocity.y = -400

func player_slide(_delta):
if Input.is_action_just_pressed(“action”):
current_state = State.Slide
velocity.x = 1000
is_sliding = true
slide_timer = slide_duration

func player_animations():
if current_state == State.Idle:
animated_sprite_2d.play(“idle”)
elif current_state == State.Run:
animated_sprite_2d.play(“run”)

if Input.is_action_pressed("crouch_press"):
	animated_sprite_2d.play("crouch")

if current_state == State.Slide:
	animated_sprite_2d.play("slide")

if velocity.y > 0 :
	animated_sprite_2d.play("jump fall")
elif velocity.y < 0 :
	animated_sprite_2d.play("jump")

if current_state == State.Jump and velocity.y <= 1 :
	has_spun = false
	animated_sprite_2d.play("jump spin")
	has_spun = true

func _on_jump_spin_finished():
if is_on_floor():
has_spun = false

  1. About the sliding:
    You’re using neither the is_sliding variable nor the slide_timer.
    For your slide_timer, you should probably make it a float instead of an int, reduce it by delta in _physics_process()and set is_sliding to false, when slide_timer <= 0.
    While is_sliding is true, probably none of the functions above move_and_slide() in _physics_process() should be executed (maybe except player_falling(), depending on how you want the slide to behave).
code changes for sliding
var slide_timer: float = 0.0
var is_sliding := false
func _physics_process(delta): # this gets more changes later

	if slide_timer <= 0:
		is_sliding = false
	else:
		slide_timer -= delta

	if not is_sliding:
		player_falling(delta) # can also be before this if-statement
		player_idle(delta)
		player_run(delta)
		player_jump(delta)
		player_slide(delta)
	
	move_and_slide()
	
	player_animations()
  1. About the crouching:
    In player_idle(), you are first checking if the player is on the floor, and then you have an elif, which is not getting checked in case the previous if condition was true. So currently, you are never entering crouch mode (you only play the crouch animation because it’s not depending on is_crouching). You should change the order of the if-statements to solve this. But you also need to implement a way for is_crouching to reset to false and to actually prevent movement/sliding:
code changes for crouching
func _physics_process(delta): # final version

	if slide_timer <= 0:
		is_sliding = false
	else:
		slide_timer -= delta

	if not is_sliding:
		player_falling(delta) # can also be before this if-statement
		player_idle(delta)
		if not is_crouching:
			player_run(delta)
			player_jump(delta)
			player_slide(delta)
	
	move_and_slide()
	
	player_animations()
func player_idle(_delta):
	is_crouching = false
	if is_on_floor() and Input.is_action_pressed(“crouch_press”):
		is_crouching = true
		current_state = State.Crouch
	elif is_on_floor():
		current_state = State.Idle
  1. About the spinning:
    Because you check if velocity.y > 0 and velocity.y < 0 (to play either “jump” or “jump fall”) before checking if velocity.y <= 1 (to play “jump spin”), the animation is constantly getting restarted.
    Also, you are once more not using the variables you have (has_spun in this case).
    You should probably make the animations consistent to the current_state variable and just use a match-statement: (This might require some additional adjustments to how current_state is changed though.)
code changes for spinning
var shall_spin := false # this replaces 'has_spun'
func player_jump(_delta):
	if Input.is_action_just_pressed(“jump_press”):
		current_state = State.Jump
		velocity.y = -400
		shall_spin = true
func player_animations():
	
	if not is_on_floor() and current_state != State.Slide:
		current_State = State.Jump
	
	match current_state:
		State.Idle:
			animated_sprite_2d.play(“idle”)
		State.Run:
			animated_sprite_2d.play(“run”)
		State.Crouch:
			animated_sprite_2d.play(“crouch”)
		State.Slide:
			animated_sprite_2d.play(“slide”)
		State.Jump: # this is used as an overall 'in air' state here
			if velocity.y < 0:
				animated_sprite_2d.play("jump")
			elif shall_spin:
				animated_sprite_2d.play("jump spin")
			else:
				animated_sprite_2d.play("jump fall")
func _on_jump_spin_finished():
	shall_spin = false

And for future reference, please format code like this:

```gd
# code here
```

1 Like