Unable to make jumping work

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

Hi all I hope you are are well,
I been unable to make jumping work on this player script, basicaly when I press up it goes up and up, also when jumping the player stops gong to the side, goes to full stop and up, what did I do wrong?

extends KinematicBody2D

const GRAVITY = 500;
const MOVE_SPEED = 10.0;
const JUMP_HEIGHT = 500;
const JUMP_SPEED = 500;

enum MoveDirection { UP, LEFT, RIGHT, NONE }

slave var slave_position  = Vector2();
slave var slave_movement = MoveDirection.NONE

#var score = 0;

func _ready():
	set_process_input(true)

func _physics_process(delta):
	var friction = false;
	var direction = null
	if Input.is_action_pressed('ui_up'):
		direction = MoveDirection.UP
	elif Input.is_action_pressed('ui_right'):
		direction = MoveDirection.RIGHT
	elif Input.is_action_pressed('ui_left'):
		direction = MoveDirection.LEFT
	else:
		direction= MoveDirection.NONE

	_move(direction)


func _move(direction):
	match direction:
		MoveDirection.NONE:
			move_and_slide(Vector2(0, GRAVITY))
			_toon_idle()
		MoveDirection.UP:
			move_and_slide(Vector2(0, -JUMP_HEIGHT))
			_toon_jump()
		MoveDirection.LEFT:
			move_and_collide(Vector2(-MOVE_SPEED, 0))
			_toon_left()
		MoveDirection.RIGHT:
			move_and_collide(Vector2(MOVE_SPEED, 0))
			_toon_right()

func _toon_idle():
	$toon.play("idle")

func _toon_jump():
	if is_on_floor():
		#$toon.position.y += abs($toon.position.y)
		$toon.play("jump")

func _toon_right():
	#$toon.position.x = abs($toon.position.x)
	$toon.flip_h = false
	$toon.play("run")

func _toon_left():
	#$toon.position.x = -abs($toon.position.x)
	$toon.flip_h = true
	$toon.play("run")
:bust_in_silhouette: Reply From: Oen44

If you want to make jumping as good as possible then use RigidBody2D. Made some tests, written simple movement script and it’s working very well. If you are going to stay with KinematicBody2D then proper jumping will be harder to achieve.

extends RigidBody2D

const MOVE_SPEED = 10;
const JUMP_HEIGHT = 50;

enum MoveDirection { UP, LEFT, RIGHT, NONE }

var velocity = Vector2()

func _ready():
	pass

func _integrate_forces(state):
	var direction = null
	if Input.is_action_pressed('ui_up') && linear_velocity.y == 0:
		direction = MoveDirection.UP
	elif Input.is_action_pressed('ui_right'):
		direction = MoveDirection.RIGHT
	elif Input.is_action_pressed('ui_left'):
		direction = MoveDirection.LEFT
	else:
		direction= MoveDirection.NONE

	_move(direction)
	pass

func _move(direction):
	match direction:
		MoveDirection.NONE:
			velocity = Vector2()
		MoveDirection.UP:
			set_axis_velocity(Vector2(0, -JUMP_HEIGHT))
		MoveDirection.LEFT:
			velocity.x = -MOVE_SPEED
		MoveDirection.RIGHT:
			velocity.x = MOVE_SPEED
	set_axis_velocity(velocity)

Actually it shouldn’t be too difficult implement jumping with a KinematicBody. If anything it should be easier. There are two platform demos in the asset store that uses kinematic bodies in both 2D and 3D.

SIsilicon | 2018-09-21 17:00

RigidBody is just easier and gives more realistic behavior.

Oen44 | 2018-09-21 17:07

Rigid bodies are meant for physics simulations, which are supposed to be physically accurate.
Kinematic bodies are meant for character movements. They allow movement by code, making them much more flexible. Rigid bodies, while they can be controlled by code to a point, are not as flexible when you want to code specific moves.

For example, say you want to code wall jumps. Something like that is almost trivial when using Kinematic bodies. Rigid bodies on the other hand would require you to some how figure out if you are even on a wall, and don’t get me started with getting it to stick…

Am I starting a comment war?

SIsilicon | 2018-09-21 17:49

Yes! It’s a war now! Prepare yourself!
But for real, you are right. Rigid body makes it easier but not as flexible as Kinematic body. I see that you have posted code for that so I don’t have to, but wanted to after your comment.

Oen44 | 2018-09-21 18:00

“Rigid body makes it easier but not as flexible as Kinematic body.”

I don’t see how it’s easier with a RigidBody. They’re not built with character movement and control totally in mind. Don’t get me wrong. It is possible to make a player with a Rigid body, and it does have it’s advantages. This demo proves it.

SIsilicon | 2018-09-21 21:30

But by looking at my script, it’s just easier to achieve what he needs in that specific topic. At least for me, I might be wrong, I’m not genius.

Oen44 | 2018-09-21 22:05

But there is a fatal problem in your code. Your changing the velocity in _physics_process. That could lead to weird jitters and what not. You should do that in _integrate_forces.

SIsilicon | 2018-09-21 23:39

Didn’t know that. I’m “working” with Godot for a few days now, and mostly 3D (C# only) so there’s that. Edit applied, thanks.

Oen44 | 2018-09-22 10:02

:bust_in_silhouette: Reply From: SIsilicon

Have you looked at the 2D platform demo? The way you are implementing character movement is not very good.

The first problem looks like it happened due to the fact that once you press up, you keep applying the jump height velocity. Causing it to pretty much “fall up” until it hits a floor.

The second problem is so because you’re character is not adding velocity. It is setting it.

Both of these problems, plus others that may arise along the way can be solved by storing a velocity variable. var linear_velocity = Vector2(). And use this with move_and_slide instead. If you want to apply forces to your character, like jump for instance, you add that force to linear_velocity and it gets taking care of by move_and_slide.

So here’s how it should work.

#the following code is inside physics_process. Note that linear_velocity was defined outside of this function.

direction = MoveDirection.NONE

#First we add gravity to the velocity.
linear_velocity.y += GRAVITY

#Apply horizontal friction. So that the character doesn't slide forever.
linear_velocity.x *= 0.0

#We then check if the player wants to move left or right.
#And if so, add a horizontal force to linear_velocity.
if Input.is_action_pressed("ui_left"):
    linear_velocity.x -= MOVE_SPEED
    direction = MoveDirection.LEFT
if Input.is_action_pressed("ui_right"):
    linear_velocity.x += MOVE_SPEED
    direction = MoveDirection.RIGHT

#Check if you can and should jump.
if is_on_floor() and Input.is_action_just_pressed("ui_up"):
    #And if so, add a vertical force going up.
    linear_velocity.y -= JUMP_SPEED

if not is_on_floor():
    direction = MoveDirection.UP

#The most important step. Setting linear_velocity to the result of move_and_slide.
linear_velocity = move_and_slide(linear_velocity, Vector2(0, -1))

#Change animation according to direction.
match direction:
    MoveDirection.NONE:  _toon_idle()
    MoveDirection.UP: _toon_jump()
    MoveDirection.LEFT: _toon_left()
    MoveDirection.RIGHT: _toon_right()

Please read the comments if you want to understand what’s going on.

By the by, I written all that without testing it, but in theory it should work. If there is a problem, let me know.

SIsilicon | 2018-09-21 17:43

Hey thanks man Im getting very close, just one more little question, after my changes I ended up with this:

extends KinematicBody2D

var direction = null;
const MOVE_SPEED = 1000;
const JUMP_SPEED = 1000;
const GRAVITY = 150;
enum MoveDirection { UP, LEFT, RIGHT, NONE }
var linear_velocity = Vector2();

func _ready():
	set_process_input(true)
	pass

func _physics_process(delta):
	direction = MoveDirection.NONE
	linear_velocity.y += GRAVITY
	linear_velocity.x *= 0.0

	if Input.is_action_just_pressed("ui_left"):
		linear_velocity.x -= MOVE_SPEED
		direction = MoveDirection.LEFT

	if Input.is_action_just_pressed("ui_right"):
		linear_velocity.x += MOVE_SPEED
		direction = MoveDirection.RIGHT

	if is_on_floor() and Input.is_action_just_pressed("ui_up"):
		linear_velocity.y -= JUMP_SPEED
	if not is_on_floor():
		direction = MoveDirection.UP

	linear_velocity = move_and_slide(linear_velocity, Vector2(0, -1))

	match direction:
		MoveDirection.NONE: _toon_idle()
		MoveDirection.UP: _toon_jump()
		MoveDirection.LEFT: _toon_left()
		MoveDirection.RIGHT: _toon_right()


func _toon_idle():
	$toon.play("idle")

func _toon_jump():
		$toon.play("jump")

func _toon_right():
	$toon.flip_h = false
	$toon.play("run")

func _toon_left():
	$toon.flip_h = true
	$toon.play("run")

Jumping definitely works a lot better, but moving has gotten funny, I have to be pressing either left or right repeatedly to be able to move a little bit. where did I messed up? :slight_smile:

rafah | 2018-09-21 19:04

Change is_action_just_pressed to is_action_pressed

Oen44 | 2018-09-21 19:53

Yes that’s right. In my example code I used is_action_just_pressed for the jump’s if condition. The difference between the two functions is that when you trigger the specified action, is_action_just_pressed becomes true for only one frame, while is_action_pressed stays true until you release the action’s trigger.

So do what Oen44 said, but only for “ui_ left” and “ui_ right”.

SIsilicon | 2018-09-21 21:17