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 ;)

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

bear_velocity.y += GRAVITY

bear_velocity = move_and_slide(bear_velocity, FLOOR)
``````
in Engine

+1 vote

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.

by (7,934 points)

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):

https://oldgameshelf.com/super-mario-bros-1217.html

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.

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
``````
by (24 points)