0 votes

Hi!

I have a player, a KinematicBody2D, that moves around using the arrow keys using move_and_slide(). The "slide" part of move and slide is important to me, as I have 45° slopes in this platformer game, on which the player can roll up and down. An integral part of the game is the ability to use WASD to bounce. For example, if you're falling down and holding S as you hit the ground, you will bounce back up with 75% of the velocity you hit the ground with. If you hit one of said 45° slopes, you will bounce to the left or right accordingly, as well as bouncing upwards.

This works for the most part, but it is sometimes buggy. Sometimes it results in unexpected behaviour such as the player coming to a complete stop or even rolling uphill a little. I think the way I have implemented the bounce is a little jerry-rigged, and I would like to ask how you would go about it?
I'm using is_on_floor() twice to check if the player hits the ground. Once before the move_and_slide() method and once after. Here is the movement code that goes in my player's script, which is getting called every frame in the _physics_process(delta) (I've removed some of the code that's only relevant for bouncing on the walls and ceiling):

# global variables in player script:
const GRAVITY_VEC = Vector2(0, 900)
const FLOOR_NORMAL = Vector2(0, -1)
const SLOPE_SLIDE_STOP = 25.0     

# bouncing
var last_vel = Vector2(0, 0)
var BOUNCE_VEL_REQUIRED_DOWN = 0.01
var bounce_coefficient = 0.75

func movement(delta: float) -> void: # called every frame
    # Find collision status, move, then find collision status again.
    var on_floor_0 = is_on_floor()
    linear_vel += delta * GRAVITY_VEC
    linear_vel = move_and_slide(linear_vel, FLOOR_NORMAL, SLOPE_SLIDE_STOP)
    var on_floor_1 = is_on_floor()

    """ Bounce on floor with S """
    # bounce on floor
    if Input.is_action_pressed("s"):
        if last_vel.y >= BOUNCE_VEL_REQUIRED_DOWN: 
            if on_floor_0 != on_floor_1: # If you've just hit the floor
                linear_vel.y = last_vel.y * -bounce_coefficient

    # Movement controls (removed parts irrelevant for this post, such as jumping)
var target_speed = 0
if not viewing_UI:
    if Input.is_action_pressed("move_left"):
        target_speed -= 1
    if Input.is_action_pressed("move_right"):
        target_speed += 1

    # movement
target_speed *= WALK_SPEED # == 1550
linear_vel.x = lerp(linear_vel.x, target_speed, 0.016)

#store info for next frame
last_vel = linear_vel

Edit: I can reproduce the bug by falling straight down, not moving along the x-axis at all.

Example: https://imgur.com/JeEwDw5

In this example (image), the player falls straight down and when he tries to bounce, he actually rolls up the slope a little bit. However if he moves a little on the x-axis before hitting the slope under the arrow, he will bounce properly - a little up and to the left, like he is supposed to.

Godot version 3.2
in Engine by (21 points)
edited by

1 Answer

+1 vote

You can apply the velocity according to the normal of the collision: velocity += get_slide_collision(0).normal * force

by (26 points)

Thank you.
Couldn't get it to work, and I suspect it's because of this line: linear_vel = move_and_slide(linear_vel, FLOOR_NORMAL, SLOPE_SLIDE_STOP). I probably have to rewrite the entire move method to use move_and_collide() rather than move_and_slide() and then adjust the player's behaviour according to different normals, rather than sort of plastering it on as the game develops.

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 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 webmaster@godotengine.org with your username.