The Godot Community Forums are back up and running! Please read the the announcement post for important information on what happened. Thanks!

Recording the time between the moment when the player is in a free fall and touching the ground

TudorTudor Posts: 35Member

Hello! I want to record, in a variable, the time between the moment when the player is in a free fall and the moment when he touches the ground, in order to implement the health loss, when jumping from a great height.

How should I do this?

Best Answer

  • TwistedTwiglegTwistedTwigleg Posts: 3,129
    Accepted Answer

    I'm not sure, but I think this will measure the time the player has been in the air (assuming a KinematicBody2D):

    var in_air_time = 0
    
    func _physics_process(delta):
        if (is_on_floor()):
            if (in_air_time > 0):
                # Make the player take damage here!
                print ("player was in the air for ", in_air_time, " seconds!")
                in_air_time = 0
        else:
            in_air_time += delta
    

Answers

  • TwistedTwiglegTwistedTwigleg Posts: 3,129Admin
    Accepted Answer

    I'm not sure, but I think this will measure the time the player has been in the air (assuming a KinematicBody2D):

    var in_air_time = 0
    
    func _physics_process(delta):
        if (is_on_floor()):
            if (in_air_time > 0):
                # Make the player take damage here!
                print ("player was in the air for ", in_air_time, " seconds!")
                in_air_time = 0
        else:
            in_air_time += delta
    
  • TudorTudor Posts: 35Member

    Awesome explanation! :)

    Yes, this code measures very well the time spent in the air.

    Thanks!

  • cyberealitycybereality Posts: 1,053Moderator

    Nice solution.

  • AzedaxenAzedaxen Posts: 50Member
    edited September 9

    If you're implementing fall damage, I think an easier and more realistic way to do so would be to damage the player based on their downward velocity when they hit the ground. It might not be necessary for your game, but this would allow you to implement things like pools of water that cushion the player's fall.

  • TudorTudor Posts: 35Member
    edited September 9

    Good idea!

    Now, I don't have any pool of water in my game, but I will consider this solution. )

  • TudorTudor Posts: 35Member
    edited September 23

    @Azedaxen , I just met the necessity to implement the damage based on downward velocity instead of time spent in the air. =)

    When I jump off the top of the tree trunk, and then land on the same tree trunk, but nearer the ground (basically, I land on a flight zone) and then I peacefully get off the tree , when I touch the ground, the player receives damage from the time spent in the air, a few seconds ago, when he is not even falling.

    It turns out that if I stay on the base of the trunk for a minute, when I touch the ground, I will receive damage from time spent in the air a minute ago. It is weird xD

    Even if this solution works very well, in order to get rid of this bug, I have to modify it.

    Do you guys know how to record the downward velocity when the player touches the ground?

    I tried a modification of the previous solution:

        if is_on_floor():
            if (in_air_time > 0):   
                print(velocity.y)
                in_air_time = 0
        elif !flying:
            in_air_time += delta
    

    but this solution measures the velocity when the player is already on the ground. The velocity is, of course, 0. ))

    I have to record the velocity just before landing.

  • AzedaxenAzedaxen Posts: 50Member
    edited September 26

    @Tudor said:
    Do you guys know how to record the downward velocity when the player touches the ground?

    Sorry, I would've seen this sooner but I've been busy.

    Ultimately, this depends on how your character controller is programmed. For instance, my character has separate variables for horizontal and vertical velocity. The reason I did this was to make it easier to handle gravity and jumping separate from the WASD movement that the player inputs. Because of this, I also have convenient access to a vertical_movement property. My fall damage code would look something like this:

    if grounded:
        if vertical_move <= -25.0:
            var falldamage = lerp(50, 100, abs(vertical_move)/terminal_velocity)
            # Player health is handled elsewhere
    

    In this example, the player starts to take fall damage if they are falling at least as fast as half of their terminal velocity, (50) and hitting the ground at terminal velocity is fatal. lerp is used to ramp the fall damage to be anywhere from a minimum of 50 to a maximum 100 based on downward speed, where vertical_move/terminal_velocity is a percentage with 100% being terminal velocity, used to interpolate between these two values.

    Edit: To further elaborate on this system, the way gravity works in my game is that the player's vertical_move is constantly being subtracted from if they are not on the ground, clamped to the terminal velocity. When they are on the ground, vertical_move is set to 0, so the check for a certain falling speed will only happen once. Setting the fall speed to 0 should happen after the fall damage check in order for this to work correctly.

    What sort of variables do you use to handle gravity?

  • TudorTudor Posts: 35Member
    edited September 27

    @Azedaxen said:
    Ultimately, this depends on how your character controller is programmed.
    What sort of variables do you use to handle gravity?

    In my game's character controller, the "velocity" variable is a Vector3(), the "gravity" is a float, and I also use a boolean variable "has_contact", to check if the player is on floor:

        var velocity = Vector3()
        var gravity = -9.8 * 3
        var has_contact = false
    

    How I handle gravity:

        var n = $Tail.get_collision_normal()
    
        if (is_on_floor()):
            has_contact = true
    
        var floor_angle = rad2deg(acos(n.dot(Vector3(0, 1, 0))))
        if floor_angle > MAX_SLOPE_ANGLE:
            velocity.y += gravity * delta
    
        else:
            if !$Tail.is_colliding():
                has_contact = false 
            velocity.y += gravity * delta
    

    where "Tail" is the player's Raycast.

    The rest of the "velocity" variable (x and z directions) are used for handle WASD movement system.

  • GogetaXGogetaX Posts: 77Member

    i would do it lil bit differently: i would take the velocity.y wich represents the speed the player falls and then calculate the dmg according to this..

    for example:
    if velocity.y > 1000 && is_on_floor():
    ..take dmg..

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Emoji
Image
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file