Problems with walking, jumping and falling animations

Godot Version

Godot_v4.2-stable_win64

Question

Hello everyone. I’ve been racking my brains for two days, hoping for your help.

  1. The falling animation doesn’t allow a second jump and dash, while playing
  2. The walking animation continues if you press the button and hold the direction button. It only turns on while moving.
  3. The jumping animation (or falling, if you turn it on) near the wall and on the floor loops
extends CharacterBody2D
enum {
	IDLE,
	WALKING,
	MOVE,
	JUMP,
	JUMP2,
	FALL,
}
const WALK = SPEED/6
const DASH_SPEED = 1200
const SPEED = 600.0

@export var jump_height : float
@export var jump_time_to_peak : float
@export var jump_time_to_descent : float

@onready var jump_velocity : float = ((2.0 * jump_height) / jump_time_to_peak) * -1.0
@onready var jump_gravity : float = ((-2.0 * jump_height) / (jump_time_to_peak * jump_time_to_peak)) * -1.0
@onready var fall_gravity : float = ((-2.0 * jump_height) / (jump_time_to_descent * jump_time_to_descent)) * -1.0

@onready var anim = $AnimatedSprite2D
@onready var animPlayer = $AnimationPlayer

var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
var jump_number = 2
var state = MOVE
var dashing = false
var can_dash = true
var jumping = true

func _physics_process(delta: float) -> void:
	match state:
		MOVE:
			move_state()
		WALKING:
			walking_state()
		JUMP:
			jump_state()
		JUMP2:
			jump2_state()
		FALL:
			fall_state()
		DASH:
			dash_state()

	move_and_slide()
if not is_on_floor(): velocity.y += get_gravity() * delta
Global.player_pos = self.position
	
	#if velocity.y > 0:
		#state = FALL
	#elif velocity.y < 0:
		#if jump_number > 0:
			#state = JUMP
		#else:
			#state = JUMP2
func move_state ():
	var direction := Input.get_axis("left", "right")
	if direction == -1:
		$AnimatedSprite2D.flip_h = true
	elif direction == 1:
		$AnimatedSprite2D.flip_h = false
	if direction:
		if dashing:
			stats.stamina_cost = stats.dash_cost
			velocity.x = direction * DASH_SPEED
		else:
			velocity.x = direction * SPEED
		if velocity.y == 0 and is_on_floor_only():
			animPlayer.play("Run")
	else:
		velocity.x = 0
		if velocity.y == 0:
			animPlayer.play("Idle")
	if Input.is_action_just_pressed("Dash") and direction:
		velocity.x = direction * DASH_SPEED
		state = DASH
	if direction and Input.is_action_just_pressed("Walk") and is_on_floor_only():
		velocity.x = direction * WALK
		state = WALKING
	#if velocity.y != 0: #and !Input.is_action_just_pressed("Dash") or !Input.is_action_just_pressed("Jump2"):
		#state = FALL
	if Input.is_action_just_pressed("Dash") and can_dash and stats.stamina > stats.stamina_cost:
		dashing = true
		can_dash = false
		$DashTimer.start()
		$DashTimer/DashAgain.start()
	if jumping:
		if is_on_floor():
			jump_number = 2
		if Input.is_action_just_pressed("Jump") and is_on_floor():
			stats.stamina_cost = stats.jump_cost
			velocity.y = jump_velocity
			state = JUMP
		if Input.is_action_just_pressed("Jump") and is_on_floor() or Input.is_action_just_pressed("Jump") and jump_number > 0 and stats.stamina > stats.stamina_cost:
			velocity.y = jump_velocity
			jump_number = jump_number - 1
			state = JUMP2
func walking_state():
	animPlayer.play("Walking")
	if Input.is_action_just_released("Walk"):
		animPlayer.play("Idle")
		state = MOVE
func jump_state():
	animPlayer.play("Jump")
	await animPlayer.animation_finished
	state = MOVE
func jump2_state():
	animPlayer.play("Jump")
	#await animPlayer.animation_finished
	state = MOVE
func fall_state():
	animPlayer.play("Fall")
	#await animPlayer.animation_finished
	state = MOVE

paste your script between three ticks like so, you can use the </> button or ctrl+e in the forum to make this for you

```
type or paste code here
```

1 Like

Thanks for the advice, I corrected the post

1 Like

Maybe you can at least help fix the looping of falling near the walls. I’ll cut out the walking. I hope you can help with something. Here’s my all code.

video:
https://t.me/c/1665040781/351/61219

  1. Your double jump logic is in the move_state function, try moving it to jump_state and/or jump2_state
  2. Similarly the walking state does not do anything to change direction, that’s handled in move_state
  3. Seems like JUMP state will never be set since JUMP2 satisfies all the same conditions, try using elif on your jumping conditions. not sure why it’s looping, seems like it would be cut off often
1 Like

I have been studying the engine for 2 months, could you help me with writing this code. If it is not too much trouble for you. I understand what you mean, but not yet enough to know where and what to insert. If you do not want to help, I will understand and what you have presented above is already better than nothing

1 Like

and I once again, for the second time, added move_and_slide
I reduced the speed because it doubles, but part of the code started working correctly, except for the walk. I will cut walking out of my life as well)

Sorry if something is wrong, English is not my native language

I would not add move_and_slide twice, it’s in a great spot inside _physics_process. Two of those can cause strange collision issues.


Most of the issues you are having are because you have added a “State Machine” but only one state does much. It might be better for you to remove the State Machine, or split your func move_state() into the other states.

For instance let’s look at walking. To get there you must press walk, and be on the floor.

if direction and Input.is_action_just_pressed("Walk") and is_on_floor_only():
	velocity.x = direction * WALK
	state = WALKING

Note how the velocity.x is set here, this is where any movement will come from. Then state = WALKING is set, so we will not return to move_state until state is set again. So let’s see what happens in walk_state.

func walking_state():
	animPlayer.play("Walking")
	if Input.is_action_just_released("Walk"):
		animPlayer.play("Idle")
		state = MOVE

We can see it plays the “Walking” animation, that’s good. Then it checks if we released the “Walk” action, plays a new animation (we could remove this) and state = MOVE so we’re back to moving.

But it never sets velocity.x = ??? we should add that logic to walking too, or else we walk in the same direction forever regardless of input. Most of these states should take input, not just play animations!

func walking_state():
	animPlayer.play("Walking")
	var direction := Input.get_axis("left", "right")
	velocity.x = direction * WALK

	if Input.is_action_just_released("Walk") or direction.is_zero_approx():
		animPlayer.play("Idle")
		state = MOVE
1 Like

Ooooh, so, yes, I began to understand. The only thing is that now It began to swear at this, but I think I will figure it out. Thank you very much for your help.
error text - is_zero_approx - cannot find property on base float

a right it would be is_zero_approx(direction)

1 Like