Player cannot jump while on angled floor

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By bribat123

In my game the player(KinematicBody2D) cannot jump when on angled floors, even though the angle of the floor is less than the floor_max_angle. I am using move__and__slide__with__snap.

How can I enable my player to jump on angled floors?

:bust_in_silhouette: Reply From: fershopls

I don’t know exactly why your code is doing that

A workarround could be attach a RayCast2D to your player and check if it is touching the floor to allow jumping

Thanks for your response. Yes using RayCast to determine if my character is on the floor is more reliable than the other methods.

bribat123 | 2020-03-03 16:58

:bust_in_silhouette: Reply From: njamster

You should read the documentation more carefully:

floor_max_angle is the maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall. The default value equals 45 degrees.

So it has nothing to do with your player’s ability to jump, it just determines what a call to is_on_floor() will return, depending on the orientation of the collider.

Furthermore it clearly states the solution to your problem:

As long as the snap vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting snap to (0, 0) or by using move_and_slide instead.

I did read the documentation and the slope angle is less than 45 degrees and the snapping is properly set.

bribat123 | 2020-03-03 16:56

Then you probably should provide some more details, like the script you’re using or an example project. I couldn’t reproduce your problems, here’s my code:

extends KinematicBody2D

var velocity = Vector2.ZERO

const FLOOR_NORMAL = Vector2.UP
const STOP_ON_SLOPE = true
const NO_SNAP = Vector2.ZERO
const VERY_LONG_SNAP = Vector2.DOWN * 1000

func _physics_process(delta):
	var snap_vector = VERY_LONG_SNAP

	velocity.y += 98 * delta

	if is_on_floor() and Input.is_action_just_pressed("ui_accept"):
		snap_vector = NO_SNAP
		velocity.y = -100

	velocity = move_and_slide_with_snap(velocity, snap_vector, FLOOR_NORMAL, STOP_ON_SLOPE)

The slope I’m using is just a StaticBody2D with a rectangular CollisionShape2D. It’s not necessary to set STOP_ON_SLOPE to true, but it makes testing a bit easier, as you won’t slide down as long as the slope is considered a floor, i.e. not rotated by more than 45° (clockwise or anti-clockwise, doesn’t matter). VERY_LONG_SNAP ensures that the snap vector will likely touch the ground, no matter the size of your character. If it is too small, it won’t. But then you should be able to jump anyways.

njamster | 2020-03-03 18:01

Thanks for your response.

I will put together a small example project and give your script a try with the player node.

bribat123 | 2020-03-03 18:57

I created a new simple project and added the code you provided. As you said it is working fine. Now I need to figure out what is different in my project that causes it to fail.

bribat123 | 2020-03-04 15:24

I created another project, this time I am correctly moving the sloped platform as in my original project. Now I am seeing the same problem where the player cannot jump from a moving sloped floor. Here is the script:

extends Node2D

const FLOOR_NORMAL = Vector2.UP
const GRAVITY = 1200
const SCROLL_SPEED = 550
const STOP_ON_SLOPE = true
const NO_SNAP = Vector2.ZERO
const VERY_LONG_SNAP = Vector2.DOWN * 1000

# Declare member variables here. Examples:
var velocity = Vector2.ZERO
var snap_vector = Vector2.ZERO

# Called when the node enters the scene tree for the first time.
func _ready():

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta):
	$Level/Area2D.position = $Level/Area2D.position + (Vector2(-1*SCROLL_SPEED,0) * delta)
	if($Player/Body.is_on_floor() == true):
		velocity.y += delta
		snap_vector = VERY_LONG_SNAP
			velocity.y = -800
			snap_vector = NO_SNAP
		velocity.y += GRAVITY * delta
		snap_vector = NO_SNAP
	velocity = $Player/Body.move_and_slide_with_snap(velocity,snap_vector,FLOOR_NORMAL,STOP_ON_SLOPE)

The player is simply a KinematicBody2D with a rectangle CollisionShape2D. The floor is a StaticBody2D with a rectangle CollisionShape2D. The moving level is an Area2D that contains a StaticBody2D and that StaticBody2D contains a rectangle CollisionShape2D.

Whenever the level collision shape is not angled, the player is able to jump fine from it. However when I add even a slight angle (-5 degrees) then the call to move-and-slide-with-snap is returning the following velocity vector (69.64032,-5.960207). This is very troublesome as it causes the player to not jump. What else can I try to resolve this??

bribat123 | 2020-03-10 03:53

I was able to get the move-and-slide-with-snap() to jump properly on an angled floor. Here is what I had to do to make it work…

First here is what my simple scene looks like:

I have a Main scene which instances a Player scene, a Level scene, and a Floor scene. The code snippet I pasted above is contained in the script attached to the Main scene. Referring to the code snippet I pasted above, as the game plays the Level scene is scrolled from right to left. The Floor does not move. The Level scene consists of a StaticBody2D and a rectangle CollisionShape2D. The Floor is the same, consisting of a StaticBody2D and a rectangle CollisionShape2D. The StaticBody2D of the Level scene is rotated slightly(-5 degrees). As the Level scene is scrolling from right to left, the Player jumps onto the sloped Level and should be able to jump also when on the Level.

When I added the -5degree rotation to the Level StaticBody2D inside the Level scene itself, the Player cannot jump from the Level because the vector out from the move-and-slide-with-snap() call is (69.64032,-5.960207) when the input vector is (0,-800). When I add the -5degree rotation to the instanced Level scene within the Main scene, then the move-and-slide-with-snap() correctly returns a vector of (0,-800) when the input vector is (0,-800).

Why does setting the rotation of the StaticBody2D in the Level scene and then instancing it in the Main scene cause move-and-slide-with-snap() to fail? Why does setting the rotation of the instanced Level scene in the Main scene cause move-and-slide-with-snap() to succeed?

bribat123 | 2020-03-11 02:31