Jump animations won't play after pressing jump, only run/walk anim

Godot Version

v.4.7.2 stable steam

Question

Hello! Still very new to Godot, I want to figure out how to get a working 3D character before trying anything fancy but running into an issue with the basic jump.

The jump itself is fine, but I cant for the life of me figure out why my jump up/down animations aren’t playing. I’ve read that it could be that the animation is being overwritten by other anims but I can’t figure out how to solve it.

Here is my code:

extends CharacterBody3D
@onready var anim_player: AnimationPlayer = $Krome_styled_Punch/AnimationPlayer
@onready var anim_tree: AnimationTree = $AnimationTree
@onready var camera: Node3D = $SpringArm3D/Camera3D
const SPEED = 8
const JUMP_VELOCITY = 12

func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta
	#Jump
	if Input.is_action_just_pressed("X_button") and is_on_floor():
		velocity.y = JUMP_VELOCITY
		anim_tree.set("parameters/Movement/transition_request", "JumpUp")
	if not is_on_floor():
		anim_tree.set("parameters/Movement/transition_request", "JumpDown")
	
	# Get the input direction and handle the movement/deceleration.
	var input_dir := Input.get_vector("Move_left", "Move_right", "Move_up", "Move_down")
	var direction := (camera.global_basis * Vector3(input_dir.x, 0, input_dir.y))
	direction = Vector3(direction.x, 0, direction.z).normalized() * input_dir.length()
	if direction:
		velocity.x = direction.x * SPEED
		velocity.z = direction.z * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		velocity.z = move_toward(velocity.z, 0, SPEED)

	move_and_slide()
	turn_to(direction)
	
	var current_speed := velocity.length()
	const RUN_SPEED = 8
	
	if current_speed > 4.5:
		anim_tree.set("parameters/Movement/transition_request", "Run")
	elif current_speed > 0.0:
		anim_tree.set("parameters/Movement/transition_request", "Walk")
		var walk_speed:= lerpf(0.5, 1.75, current_speed / RUN_SPEED)
		anim_tree.set("parameters/walk_speed/scale", walk_speed)
	else:
		anim_tree.set("parameters/Movement/transition_request", "Idle")
	
func turn_to(direction: Vector3) -> void:
	if direction.length() > 0:
		var yaw := atan2(-direction.x, -direction.z)
		yaw = lerp_angle(rotation.y, yaw, 0.25)
		rotation.y = yaw

I was following this video https://youtu.be/L4EYYogZlBA?si=R9U6JrDhX-_xPu5I I’ve done everything but lean code/anim since I didn’t feel it needed it, they managed to get the fall animation to play when they walk off a ledge but on my side it won’t work for some reason. Here is the animation tree just in case that’s part of the issue:

I should mention that I planned to have my jump animation in 2 parts, one for jumping upwards and the other for when the player is actively falling. Any help would be greatly appreciated!!

These lines overwrite the jump animations with walk, run, idle animations. If you added “and !is_on_floor()” to the if condition, part of the problem would go away. You jumpup animation would only ever last one frame at most though, as you check if on floor and input is jump. The frame after, is_on_floor() will no longer return true, and animation jumpdown will play instead. Unless you have something not visible here to prevent that from happening.

Had a feeling that part of the code was messing with it, I’ve added the and !is_on_floor() to the if condition but it seems to have made it so now the walk is the new run but sped up and run is the new jump animation. The jump anims don’t show up period (not that I can see at least)

do lmk if I’ve just chucked this into the wrong spot though

You do elif current_speed greater than 0, walk. Again, this will overwrite any previous animation if your speed is greater than 0. Exception only if the animation gets set by the if current_speed > 4.5 and !is_on_floor() right before.

Another problem with if current_speed > 4.5 and !is_on_floor() is that you set the run animation only when not on floor. “!” Is the same as “not” or false here. So you should remove it.

I would do like this:

var just_pressed_jump_timer: float

func _physics_process(delta):

just_pressed_jump_timer -= delta

if Input.is_action_just_pressed("X_button") and is_on_floor():
	velocity.y = JUMP_VELOCITY
    just_pressed_jump_timer = whatever time you want the animation to play while in the air

If is_on_floor():

     if current_speed > 4.5:

          Run animation

     Elif current_speed > 0:

          Walk animation

     Elif !current_speed:

          Idle

elif !is_on_floor():
     if just_pressed_jump_timer > 0: 
          jump up animation
     else: 
          jump down animation 

It kind of makes sense to make an initial check if you are grounded or not grounded and group the possible animations depending on the outcome, so that you don’t end up with a mess of mixed animations all checking !is_on_floor and this or that or is_on_floor and this or that. It will be easier to work with having the possible animations grouped into different little clusters like this.

The just_jumped_timer is just an idea, you could go for any other option, like jump up playing while holding jump or until the animation emits the finished signal or anything else, but at least this way you will avoid it only lasting for one frame. I would personally go for either the timer or playing jumpup and adding a bit to upwards velocity while holding jump pressed.

this has def moved things in the right direction, I still don’t get an animation when I jump but when the player stands still when pressing jump its in its idle anim, while I move it keeps the running/walking anim without jittering between animations like it was before. Here’s my code again, could I have just put things in the wrong slot and that’s why its still not showing? Forgive me if I have, I get a little confused where to put certain code sometimes!

extends CharacterBody3D
@onready var anim_player: AnimationPlayer = $Krome_styled_Punch/AnimationPlayer
@onready var anim_tree: AnimationTree = $AnimationTree
@onready var camera: Node3D = $SpringArm3D/Camera3D
const SPEED = 8
const JUMP_VELOCITY = 12
var just_pressed_jump_timer: float

func _physics_process(delta: float) -> void:
	
	
	if not is_on_floor():
		velocity += get_gravity() * delta
	just_pressed_jump_timer -= delta
	#Jump
	if Input.is_action_just_pressed("X_button") and is_on_floor():
		velocity.y = JUMP_VELOCITY
		just_pressed_jump_timer = 2

		
	# Get the input direction and handle the movement/deceleration.
	var input_dir := Input.get_vector("Move_left", "Move_right", "Move_up", "Move_down")
	var direction := (camera.global_basis * Vector3(input_dir.x, 0, input_dir.y))
	direction = Vector3(direction.x, 0, direction.z).normalized() * input_dir.length()
	if direction:
		velocity.x = direction.x * SPEED
		velocity.z = direction.z * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		velocity.z = move_toward(velocity.z, 0, SPEED)

	move_and_slide()
	turn_to(direction)
	
	var current_speed := velocity.length()
	const RUN_SPEED = 8
	
	if is_on_floor():
		if current_speed > 4.5:
			anim_tree.set("parameters/Movement/transition_request", "Run")
		elif current_speed > 0.0:
			anim_tree.set("parameters/Movement/transition_request", "Walk")
			var walk_speed:= lerpf(0.5, 1.75, current_speed / RUN_SPEED)
			anim_tree.set("parameters/walk_speed/scale", walk_speed)
		elif !current_speed:
			anim_tree.set("parameters/Movement/transition_request", "Idle")
		
		elif !is_on_floor():
			if just_pressed_jump_timer > 0:
				anim_tree.set("parameters/Movement/transition_request", "JumpUp")
		else:
			anim_tree.set("parameters/Movement/transition_request", "JumpDown")
	
func turn_to(direction: Vector3) -> void:
	if direction.length() > 0:
		var yaw := atan2(-direction.x, -direction.z)
		yaw = lerp_angle(rotation.y, yaw, 0.25)
		rotation.y = yaw

Yes, you keep the !is_on_floor(): indented one level. This means it can only be reached by first passing the initial is_on_floor() check. Which means it will never run, since it can not be true and false at the same time.

So the stuff that is beneath here, should be as far to the left as the if is_on_floor(): on the top

elif !is_on_floor():
if just_pressed_jump_timer > 0:
anim_tree.set(“parameters/Movement/transition_request”, “JumpUp”)
else:
anim_tree.set(“parameters/Movement/transition_request”, “JumpDown”)

You’re an absolute legend, thank you so much! it works great now going up and down, thanks for all the help!!

No worries! Glad it is working now!