+1 vote

I'm following Game Endeavor 2D platformer series, in his "Improve Your Game Feel With Coyote Time and Jump Buffering" tutorial I'm trying to add Jump Buffering and Let the player control the height of the jump, The problem is when player jump in mid-air it jumps to max height even when he barely press the jump key, but when it grounded he can control jump height normally

This is the whole project if you want to see it: https://github.com/yznhamzeh/my_first_platformer/tree/master/platformer_0.1

This is the player code :

extends KinematicBody2D

signal grounded_updated(is_grounded)

const UP = Vector2(0, -1)

var velocity = Vector2()
var move_speed = 100
var gravity 
var max_jump_velocity 
var min_jump_velocity
var is_grounded
var is_jumping

onready var raycasts = $RayCasts
onready var anim_player = $AnimationPlayer
onready var coyote_time = $CoyoteTimer
onready var jump_buffer = $JumpBuffer

var max_jump_height = 5.25 * 16
var min_jump_height = 2 * 16
var jump_duration = 0.5


func _ready():
    gravity = 2 * max_jump_height / pow(jump_duration, 2)
    max_jump_velocity = -sqrt(2 * gravity * max_jump_height)
    min_jump_velocity = -sqrt(2 * gravity * min_jump_height)

func _physics_process(delta):

    _apply_gravity(delta)

    var was_on_floor = is_grounded

    _get_input()

    velocity = move_and_slide(velocity, UP)

    var was_grounded = is_grounded

    is_grounded = _check_is_grounded()

    if was_grounded == null || is_grounded != was_grounded:
        emit_signal("grounded_updated", is_grounded)

    _assign_animation()

    if !is_grounded && was_on_floor && !is_jumping:
        coyote_time.start()
        velocity.y = 0
    if is_grounded && !jump_buffer.is_stopped():
        jump_buffer.stop()
        jump()





func _apply_gravity(delta):
    if coyote_time.is_stopped():
        velocity.y += gravity * delta
        if is_jumping && velocity.y >= 0:
            is_jumping = false



func _input(event):
    if event.is_action_pressed("jump") :
        if is_grounded || !coyote_time.is_stopped():
            coyote_time.stop()
            jump()
        else:
            jump_buffer.start()

    if event.is_action_released("jump") && velocity.y < min_jump_velocity:
        velocity.y = min_jump_velocity



func _get_input():
    var move_direction = -int(Input.is_action_pressed("move_left")) + int(Input.is_action_pressed("move_right"))
    velocity.x = lerp(velocity.x, move_speed * move_direction, 0.15)

    if move_direction != 0:
        $Body.scale.x = move_direction


func _get_h_weight():
    if is_grounded || !coyote_time.is_stopped():
        return 0.2
    else:
        return 1


func _check_is_grounded():
    for raycast in raycasts.get_children():
        if raycast.is_colliding():

            return true

    return false

func _assign_animation():
    var anim = "idle"

    if !is_grounded && coyote_time.is_stopped():
        anim = "jump"
    elif velocity.x > 20 or velocity.x < -20:
        anim = "run"

    if anim_player.assigned_animation != anim:
        anim_player.play(anim)

func jump():
    velocity.y = max_jump_velocity
    is_jumping = true
in Engine by (13 points)

1 Answer

0 votes

The problem occurs when the jump key is released before starting the jump, therefore the jump cannot be cancelled and will go to the max height.

You can fix this by tracking how many frames there are between the jump key being pressed and the jump key being released. When the jump starts, increment a counter each frame until the counter equals the amount of frames the jump key was held for, then cancel the jump velocity.

Here is an example (Doesn't involve coyote time however):


extends KinematicBody2D var frame_time: int = 0 export var floor_direction = Vector2(0, -1) export var max_speed: int = 1500 export var acceleration: int = 50 export var jump_height: int = -2150 export var gravity: int = 80 var jump_buffered = false var jump_start_frame : int var jump_length : int var jump_release_counter: int = 0 var is_jumping : bool = false var motion = Vector2() func _physics_process(delta): frame_time += 1 motion.y += gravity var friction = false # Left and Right movement if Input.is_action_pressed("ui_right"): motion.x += max_speed $MainSprite.flip_h = false elif Input.is_action_pressed("ui_left"): motion.x -= max_speed $MainSprite.flip_h = true else: friction = true #Jumping and buffers if Input.is_action_just_pressed("ui_up"): jump_start_frame = frame_time startBuffer() if Input.is_action_just_released("ui_up"): jump_length = frame_time - jump_start_frame if is_jumping: jump_length -= 1 if jump_length == 0: is_jumping = false jump_length = 0 if motion.y < 0: #Check needs to be made so jump cannot be cancelled when falling motion.y *= 0.5 #Set the Jump Short if is_on_floor(): if friction == true: motion.x = lerp(motion.x, 0, 0.2) if jump_buffered: is_jumping = true motion.y = jump_height else: if friction == true: motion.x = lerp(motion.x, 0, 0.1) ############################################# motion.x = clamp(motion.x , -max_speed, max_speed) motion = move_and_slide(motion, floor_direction) func startBuffer(): jump_buffered = true yield(get_tree().create_timer(0.1), "timeout") jump_buffered = false

by (14 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.