Hi,

I'm a little unsure as what I need to change, perhaps the whole code so far for movement.

I'm trying to make a classic 2D platform player movement similar to Super Mario. When the player jumps they should be able to flip direction (just the sprite), but not move_and_slide in the opposite direction. So once the direction for the movement is set, you shouldn't be able to reverse - you are committed to that direction only.

The way I have it so far is kinda neat and allows you to change your mind mid air, but it's not the right feel for what I want.

Any Ideas what to change?

# Simple Platform Movement Script

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 - Allows the jump to end when key jump button released		
	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 - adding it to bear_velocity slows the gravity down issue
	bear_velocity = move_and_slide(bear_velocity, FLOOR)

Thanks!

Hey, you movement should consider if you are grounded. Means:

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

So you will keep your movement on x axis while you are in the air and cannot change the direction. But if you are grounded, you need to press a movement-key to move, otherwise you will stand still.

Some additions: - If you jump right and hit a wall, your movement on the x axis will stay, so you should detect that collision and set the movement on x axis to 0. Same for movement to the left.

  • In some games, it could be good to change the direction in mid air. It depends on the challenge you want for the player. For example, look at super meat boy. This game is about fast but precise movement. It would be a pain in the a** if you could not change your direction in mid air, or even stop moving in the x axis. So you should think about the type of game you want to make. Maybe test both movement-behaviors before before you decide what you want.

Hi Schorsch, this is almost right thanks, except that the character only jumps a fixed amount left or right. The ability to jump left or right partially/variably, has gone. This leaves no control for the player to adjust the jump across to another platform.

I thought that when I added the code, I would have the same control, but as the character jumps and leaves the ground, there is no control.

Is there any way around this?

Just in case you don't have access to Super Mario, here's an online link to the game to play: https://oldgameshelf.com/super-mario-bros-1217.html

The main other difference is obviously the inertia too, next job after this is sorted!

In Super Mario, you have no control over how wide you jump left or right. You just have control about how high you jump. That said, you control passively how wide you jump. If you run right and just hit the jump button, you make a small jump and therefore you don't jump that wide. If you run right and hold the jump button pressed, you make a higher jump and therefore jump wider. There are many ways to setup a variable jump strength. I think it is easiest if you don't just detect the moment when the button get's pressed. Detect it for an amount of time.

if Input.is_action_pressed("ui_select"):
    if grounded():
        jump_time = MAX_JUMP_TIME
        bear_velocity.y = JUMP_POWER
    elif jump_time >= 0:
        bear_velocity.y += JUMP_POWER * delta
        jump_time -= delta
else:
    jump_time = 0

This code isn't tested but the idea is that you can start a jump if the player hits the key and is grounded. THerefore a variable jump_time is set. This sais how long you can press the jump key to add power to your jump. In Super Mario, this value is rather small. The time after the last frame is subtracted from this value. So when this is zero or less, you cannot add more power to your jump. The last else case is that a player can not hit jump, release it and directly hit it another time while he is in the air. That would result in some kind of double jump. Because this is over time, you have to add the delta-time in this calculation. I think the code which i wrote should work, but has some issues. In the last calculation, jump_time -= delta will normally be something less than zero. In this last calculation, you shouldn't better not use JUMP_POWER * delta, but JUMP_POWER times the rest of your "jump timer". I hope you understand what i mean.

You have something for variable jump heights in your code, but that looks to me that it isn't time restricted.

tldr: In Super Mario the power of a jump on how long you press the button and the higher you jump, the wider you jump, just because you are longer in the air.

Thanks Schorsh, I have found the answer, I was looking in the wrong place, well sort of. I had to slow down a video of Mario to see what was actually going on, then it became obvious. My code was correct, but because I was missing inertia/acceleration/deceleration it didn't behave the correct way.

Now when my character runs and jumps, when you attempt to go in the other direction you have too much forward momentum and thus cannot just move in mid-air in the opposite direction.

I haven't yet added the speeding up of the animation frames for running, i'll have to look into it.

My base code has changed, as I had to borrow from someone else's script to get it to work right. There's a few new additions that I don't quite yet understand, but I expect I will eventually, I am a noob after all.

Here's my modified code in case anyone needs it (change variables to suit):

# Mario Style Player Movement


extends KinematicBody2D
var bear_velocity = Vector2()
var on_ground = false
const ACCELERATION = 4
const MAX_SPEED = 110
const GRAVITY = 15
const FLOOR = Vector2(0,-1)
const JUMP_HEIGHT = -300
const MIN_JUMP_HEIGHT = -20

func _physics_process(delta):
		
# Add Gravity
bear_velocity.y += GRAVITY

var friction = false

	
# Walking Left, Right or Idle
if Input.is_action_pressed("ui_right"):
	#$Sprite.flip_h = false		
	bear_velocity.x = min(bear_velocity.x +ACCELERATION, MAX_SPEED)
	$Sprite.play("Walk")
	
elif Input.is_action_pressed("ui_left"):
	#$Sprite.flip_h = true
	bear_velocity.x = max(bear_velocity.x -ACCELERATION, -MAX_SPEED)	
	$Sprite.play("Walk")	
	
else:
	#bear_velocity.x = 0
	friction = true
	#if on_ground == true:
	$Sprite.play("Idle")

# Jump
if is_on_floor():
	if Input.is_action_just_pressed("ui_select"):
		bear_velocity.y = JUMP_HEIGHT
	if friction == true:
		bear_velocity.x = lerp(bear_velocity.x, 0, .2)
else:
	if bear_velocity.y < 0:
		$Sprite.play("Jump")
	else:
		$Sprite.play("Fall")
	bear_velocity.x = lerp(bear_velocity.x, 0, .05)
	
	# Variable Height Jump
	if Input.is_action_just_released("ui_select") && bear_velocity.y < MIN_JUMP_HEIGHT:
		bear_velocity.y = MIN_JUMP_HEIGHT


# Sprite Direction	
if bear_velocity.x > 0:
	$Sprite.flip_h = false
elif bear_velocity.x < 0:
	$Sprite.flip_h = true

# Add Movement from Vector2 
bear_velocity = move_and_slide(bear_velocity, FLOOR, 5, 4, PI/3)

ok :) Do you have specific questions about the code? Maybe i or someone else can help?

4 years later