Running tweens in a physics_process function

Godot Version

4.5

Question

Hi everyone, I am working a 2d Godot project specifically a player scene. The player needs to play a death animation when he crosses a specific y-coordinate. The problem is that I am checking the player sprites location in the physics_process function sense the players location is updated there. However the tweens code run at the same time as the rest of the physics_process function meaning the tweens behave weirdly if you interrupt them with a key stroke and the player is still being effected by gravity which also messes up the animation. I tryed using await but that only stops instructions after the tween from running until the tween is finished but the code earlier in the physics_process continues to run. Any ideas would be greatly appreciated. Thank in advance.

Here is the code for the player scene:

extends CharacterBody2D


const SPEED = 3.0
const JUMP_VELOCITY = -400.0

var tween : Tween


func _ready():
    var sprite_size = $BirdSprite.texture.get_size()
    position = Vector2((Global.win_size[0]/2.0) - sprite_size.x/2.0, (Global.win_size[1]/2.0) - sprite_size.y/2.0)
    print(position)
    

func _physics_process(delta):
    # Add the gravity.
    if not is_on_floor():
        print('something is wrong')
        #velocity.y = 80
        velocity += get_gravity() * delta

    # Handle jump.
    if Input.is_action_just_pressed("ui_accept"):
        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 direction = Input.get_axis("ui_left", "ui_right")
    if direction:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)

    move_and_slide()
    
    if to_global($BirdSprite.get_rect().position).y > Global.win_size.y:
        #print(to_global($BirdSprite.get_rect().position))
        #print(to_global($BirdSprite.position))
        await death_animation()
        print('timeout passed')
        get_tree().call_deferred("change_scene_to_file", "res://Scenes/game_over.tscn")


#my custom functions
func death_animation():
    #if not tween.is_running():
    print('tween start')
    tween = create_tween() # tweens will transition at the same time
    
    # Change position.x to 512 and also
    # change the scale simultaneously:
    tween.tween_property(self, "position:y", position.y - 300, 1.5)
    tween.tween_property(self, "rotation", deg_to_rad(180), 1.5)
    #tween.chain().tween_property(self, "global_position:y", global_position.y + 300, 0.5)
    
    print('tween end')
    await get_tree().create_timer(3.0).timeout

Here is the node structure for the player scene:

await is generally more confusing and error prone than it’s worth.

_physics_process will continue to run every frame, this includes a new await every frame while the animation plays. You could disable physics process while this animation plays to prevent this

if to_global($BirdSprite.get_rect().position).y > Global.win_size.y:
    set_physics_process(false) # stops _physics_process from running
    death_animation()

func death_animation():
    tween = create_tween()
    tween.tween_property(self, "position:y", position.y - 300, 1.5)
    tween.tween_property(self, "rotation", deg_to_rad(180), 1.5)

    await tween.finished # Don't create an extra timer to await
    get_tree().change_scene_to_file.call_deferred("res://Scenes/game_over.tscn")

This works perfectly thanks :smiley: