Prevent Platform Character changing jump direction when in the air

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

Hi,

I’m having difficulty changing the typical game mechanic I’ve seen in the majority of tutorials for platform game character movement with KinematicBody2D in Godot.

I’m trying to create a movement typical of 80’s platform games, such as Super Mario. Where the player jumps and cannot reverse the direction of movement. Flip the sprite, yes, but not go against physics!

The desired outcome is to force the player to only jump in the direction they chose, so they are committed to it.

It’s absolutely baffling how to implement it. I’ve attempted functions to split the controls up, but it just became too complicated as it then affected the jumping too. Plus I was creating the same code twice, which looked amateurish at best - it still didn’t work though :wink:

Anyway, here’s my basic code before I attempted to alter it:

extends KinematicBody2D

var bear_velocity = Vector2()
var on_ground = false

const SPEED = 60
const GRAVITY = 10
const FLOOR = Vector2(0,-1)
const JUMP_POWER = -242


func _physics_process(delta):
	
	
	# Walking Left, Right or Idle
	if Input.is_action_pressed("ui_right"):
		$Sprite.flip_h = false		
		bear_velocity.x = SPEED
		$Sprite.play("Walk")	
		
	elif Input.is_action_pressed("ui_left"):
		$Sprite.flip_h = true		
		$Sprite.play("Walk")		
		bear_velocity.x = -SPEED
	else:
		bear_velocity.x = 0
		if on_ground == true:
			$Sprite.play("Idle")
			
	
	# Jumping
	if is_on_floor():
		on_ground = true		
	else:
		on_ground = false
		if bear_velocity.y < 0:
			$Sprite.play("Jump")				
		else:
			$Sprite.play("Fall")
				
	
	if Input.is_action_pressed("ui_select"):
		if on_ground == true:
			bear_velocity.y = JUMP_POWER
			on_ground = false
						
	
	# Variable Height Jump		
	if Input.is_action_just_released("ui_up") && bear_velocity.y < -50:
		bear_velocity.y = -50
		
	
	# Add Gravity
	bear_velocity.y += GRAVITY
	
	# Add Movement from Vector2 
	bear_velocity = move_and_slide(bear_velocity, FLOOR)
	


	
	
:bust_in_silhouette: Reply From: eons

A way to make the player unable to change direction when not on the ground is to prevent direction change when the player is not on the grund (as you see, the question gives an answer).

if Input.is_action_pressed("ui_right") && on_ground:

For this, you will have to do the is_on_floor() check before the input handling to get the correct grounded status.

Thanks, but this causes a small issue. The character can no longer move left or right when jumping.

Someone else suggested I place the control inside the if on_floor, e.g.:

if is_on_floor():
    if Input.is_action_pressed("ui_right"): # move right if you press right-key
        bear_velocity.x = SPEED
    elif Input.is_action_pressed("ui_left"): # move left if you press left-key
        bear_velocity.x = -SPEED
    else: # don't move if you are grounded and neither left nor right key is pressed
        bear_velocity.x = 0

But that isn’t right either, again the player has no control over the amount of distance traveled left or right. The player is locked to one big jump left, or one big jump right.

Here’s a link to Super Mario for reference (forget the inertia, I have to tackle that next):

Play Retro Games Online - NES, SNES, GBA, GBC, NEO-GEO & More

JayH | 2019-02-24 14:31

If you want SMB style then the ting is different, you need to apply inertia to add speed ( stop adding on release), and SMB probably applies similar drag to floor and air.

eons | 2019-02-25 00:06

:bust_in_silhouette: Reply From: Korbie

SUPER LATE but. Hello, im also a new to godot and just happened to find a way to implement this. So basically you remove the numbers on the speed var and add a normSpeed and jumping_moveSpeed, then change the speed based on if the bear is on the air or not. something like this

var speed
var normSpeed = #your desired normal speed
var jumping_moveSpeed = #you can make it zero so they can flip but not move or just change it to a small value

func _physics_process(delta):

    if   !on_ground:
        speed = jumping_moveSpeed
    elif  on_ground:
        speed = moveSpeed

    # Walking Left, Right or Idle
    if Input.is_action_pressed("ui_right"):
        $Sprite.flip_h = false      
        bear_velocity.x = speed
        $Sprite.play("Walk")    

    elif Input.is_action_pressed("ui_left"):
        $Sprite.flip_h = true       
        $Sprite.play("Walk")        
        bear_velocity.x = -speed
    else:
        bear_velocity.x = 0
        if on_ground == true:
            $Sprite.play("Idle")

if Input.is_action_pressed("ui_select"):
    if on_ground == true:
        bear_velocity.y = JUMP_POWER
        on_ground = false