I've made controller and it works but jump animation is not working. idk what to do with that. I made jump and walk anims not loop. Pls answer the qustion (Do not write about Vector 3) The problem is only in anims.
func _input(event):
if Input.is_action_pressed("light plus"):
LIGHTLVL.light_energy += 0.1
if Input.is_action_pressed("light minus"):
LIGHTLVL.light_energy -= 0.1
if LIGHTLVL.light_energy > 1:
LIGHTLVL.light_energy = 1
if LIGHTLVL.light_energy < 0:
LIGHTLVL.light_energy = 0
func _physics_process(delta):
# Add the gravity.
if not is_on_floor():
velocity.y -= gravity * delta
# Handle Jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
if Input.is_action_pressed("ui_right"):
$AnimatedSprite2D.play("Walk")
$AnimatedSprite2D.flip_h = 0
elif Input.is_action_pressed("ui_left"):
$AnimatedSprite2D.play("Walk")
$AnimatedSprite2D.flip_h = 1
elif Input.is_action_just_pressed("ui_accept") and is_on_floor():
$AnimatedSprite2D.play("Jump")
else:
if !$AnimatedSprite2D.is_playing():
$AnimatedSprite2D.play("Idle")
move_and_slide()
Given that you jumped with:
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
If the execution flow is not entering here:
elif Input.is_action_just_pressed("ui_accept") and is_on_floor():
$AnimatedSprite2D.play("Jump")
It must be because the execution flow is entering one of the preceding conditionals:
if Input.is_action_pressed("ui_right"):
$AnimatedSprite2D.play("Walk")
$AnimatedSprite2D.flip_h = 0
elif Input.is_action_pressed("ui_left"):
$AnimatedSprite2D.play("Walk")
$AnimatedSprite2D.flip_h = 1
So, for example, if you are holding "ui_right"
or "ui_left"
and press "ui_accept"
, then the character will jump, but the play animation will not play because the blocks for the walk animation take precedence.
Presumably you want the jump to take precedence, then check for jump first:
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
$AnimatedSprite2D.play("Jump")
elif Input.is_action_pressed("ui_right"):
$AnimatedSprite2D.play("Walk")
$AnimatedSprite2D.flip_h = 0
elif Input.is_action_pressed("ui_left"):
$AnimatedSprite2D.play("Walk")
$AnimatedSprite2D.flip_h = 1
else:
if !$AnimatedSprite2D.is_playing():
$AnimatedSprite2D.play("Idle")
Addendum:
I'm interesting in conveying how to approach these problems. So before I go into it, a couple things:
walk anim plays after the 1st frame when jump
Since you the code was using is_action_just_pressed
which will only be true for one frame (physics frame in this case), it makes sense that after that frame the execution flow will go to the walk animation.
Thus, when exactly should it be playing the walk animation? The first thing that comes to mind is that it should be only when the character is on the floor.
That suggest to add a check for is_on_floor()
so that the walking animation does not play in the air. Which suggest that is it better to reorganize the checks around is_on_floor()
since jump has it too.
That will be my approach, with some extra considerations:
Something to be aware of: Your code for choosing animations is before move_and_slide
. It is move_and_slide
what updates is_on_floor()
. It also updates velocity
based on what it collides with.
So before move_and_slide
the character will have have some downwards vertical velocity because of gravity regardless if the character is on the floor.... Unless it jumped.
Let us start with the flip. It is unclear to me why you are setting an int
, but I believe this does the same you were doing:
$AnimatedSprite2D.flip_h = 1 if input_dir.x < 0.0 else 0
If you can set a bool
, it would be this:
$AnimatedSprite2D.flip_h = input_dir.x < 0.0
Note that here I'm assuming that the direction is controlled by input, not by velocity. However, you might prefer to have velocity control it:
$AnimatedSprite2D.flip_h = velocity.x < 0.0
I'll keep using velocity
below (which has the added advantage that the character will stop its animation when it stops moving, barring the fact the code is before move_and_slide
as mentioned above). However, at least for the horizontal, you could use input_dir
instead.
About the animations, I remind you that the character could be in the air because it jumped or because it is falling. The simpler approach is to only change animations on the ground.
if is_on_floor():
# ON THE FLOOR
if velocity.y > 0.0:
# ON THE FLOOR AND GOING UP
$AnimatedSprite2D.play("Jump")
elif is_zero_approx(velocity.x):
# ON THE FLOOR AND STATIONARY
$AnimatedSprite2D.play("Idle")
else:
# ON THE FLOOR AND MOVING HORIZONTALLY
$AnimatedSprite2D.play("Walk")
If you wanted to have a falling animation, then you have a decision to make: when does it switch to it?
It could be in any airborne downwards motion:
if is_on_floor():
# …
else:
if velocity.y < 0.0:
$AnimatedSprite2D.play("Fall")
It could be only when not jumped, so it does not play in the downwards part of the jump:
We need a variable to store if the character jumped (be aware that you will want to change to an int
if you want to support double-jump or any other limited multi-jump):
var jumped := false
Which means we have to set it to true
when jumping, and to false
when on the ground and not jumping (be aware that if you want to implement coyote time, or jump buffering you will have to change this code):
if is_on_floor():
if Input.is_action_just_pressed("ui_accept"):
velocity.y = JUMP_VELOCITY
jumped = true
else:
jumped = false
And finally we can apply the animation:
if is_on_floor():
# …
else:
if not jumped:
$AnimatedSprite2D.play("Fall")
Or it could be after falling for a while.
For this you want to compute the height at which it will start falling. So it is a similar setup than above:
@export var falling_offset := 0.0
var fall_height := 0.0
if is_on_floor():
fall_height = global_position.y + falling_offset
if Input.is_action_just_pressed("ui_accept"):
velocity.y = JUMP_VELOCITY
if is_on_floor():
# …
else:
if global_position.y > fall_height:
$AnimatedSprite2D.play("Fall")
And yes, presumably you have all three. And yes, the character controller can get much more complex.