All Questions

Community

W
be-we

Player still jumps automatically when reaching the top of the slope

My existing code looks different because of the simpler way to stomp.

Despite the code from this video the snapping on the slope does not work as it should. The player still jumps automatically when reaching the top of the slope.

My current Player.gd:

extends Actor
class_name Player

export var stomp_impulse: = 1000.0

func _on_StompDetector_area_entered(area: Area2D) -> void:
	_velocity = calculate_stomp_velocity(_velocity, stomp_impulse)

func _on_EnemyDetector_body_entered(body: Node) -> void:
	queue_free()

func _physics_process(delta: float) -> void:
	var is_jump_interrupted: = Input.is_action_just_released("jump") and _velocity.y < 0	var direction: = get_direction()
	_velocity = calculate_move_direction(_velocity, direction, speed, is_jump_interrupted)
	var snap: = Vector2.DOWN * 80.0 if direction.y == 0.0 else Vector2.ZERO
	_velocity.y = move_and_slide_with_snap(
		_velocity, snap, FLOOR_NORMAL, true, 4, PI / 3.0).y

		for i in get_slide_count():
		var collision := get_slide_collision(i)
		var collider := collision.collider
		var is_stomping := (
			collider is Enemy and
			is_on_floor() and
			collision.normal.dot(Vector2.UP) > 0.5
		)

		if is_stomping:
			_velocity.y = -stomp_impulse
			(collider as Enemy).kill()

func get_direction() -> Vector2:
	return Vector2(
		Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left"),
		-1.0 if Input.is_action_just_pressed("ui_jump") and is_on_floor() else 1.0
	)

func calculate_move_direction(
		linear_velocity: Vector2,
		direction: Vector2,
		speed: Vector2,
		is_jump_interrupted: bool
) -> Vector2:
	var out: = linear_velocity
	out.x = speed.x * direction.x
	out.y += gravity * get_physics_process_delta_time()
	if direction.y == -1.0:
		out.y = speed.y * direction.y
	if is_jump_interrupted:
		out.y = 0
	return out

func calculate_stomp_velocity(linear_velocity: Vector2, impulse: float) -> Vector2:
    var out: = linear_velocity
	out.y = -impulse
	return out
  • Nathan Lovato replied

    You can try to play with two parameters:

    The number "4" below, the number of slides. I don't remember if I showed this in the video but reducing it to 1 or 2 on the ground could help. It's the max number of times the character may move and collide again after a collision.

    The other parameter is the slope angle, PI / 3.0. If your slope is about the same angle, you'll get some issues.

    Could you try and tell me if it helps?

    move_and_slide_with_snap(
    	_velocity, snap, FLOOR_NORMAL, true, 4, PI / 3.0
    )
    
  • W
    be-we replied

    Hi Nathan,

    Reducing the number of slides to 2 does not change the automatic jumping of the player. After further reducing to 1, the player moves very slowly on the ground, but the automatic jumping when reaching the top of the slope is gone.

  • Nathan Lovato replied

    In this case, I would need your Godot project to solve the issue. Could you zip it and upload it somewhere?

  • W
    be-we replied

    You can download the Godot project from the following URL:

    https://share.mailbox.org/ajax/share/059b347009428d4b58a766f9428d4d99b085b20cbc4d2885/1/8/NTI/NTIvMTM

  • Nathan Lovato replied

    I see why. The condition for your snap vector to point down is never true:

    var snap: = Vector2.DOWN * 80.0 if direction.y == 0.0 else Vector2.ZERO
    

    So your never snap to the floor.

    You need to change the condition to

    if is_equal_approx(direction.y, 1.0)
    

    Note I'm using the function is_equal_approx() here instead of ==, a function added in Godot to account for processor rounding mistakes with floating point values. Using this function is robust while checking for inequality can lead to weird bugs.

    This is because get_direction() returns either -1.0 or 1.0 for the y axis,so it's never equal to 0.0:

    func get_direction() -> Vector2:
        return Vector2(
            Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left"),
            -1.0 if Input.is_action_just_pressed("ui_jump") and is_on_floor() else 1.0
        ) 
    
  • W
    be-we replied

    Great! Using the `is_equal_approx()` function has solved the problem.

    Many thanks for your detailed explanation about the problem and how to fix it.

  • G
    CrunchedCan replied

    I ran into this same issue, but I used:

    var snap: = Vector2.DOWN * 50.0 if direction.y >= 0.0 else Vector2.ZERO 
    

    This seems to work, as my direction.y should only be >= 0.0 if jumping, correct? Is there a reason I shouldn't use this?

    My jump code is still the original as I have not yet changed it based on the "simpler way to stomp" code.