I'm designing an oldschool Spectrum-like platformer where I need several jump tweaks I can't quite figure out.

Two problems with the player code below:
1. The player jumps only with

``````if Input.is_action_pressed("player_jump"):
``````

Problem with the jump sound is that it retriggers every frame, whereas I need it only to play once. Which happens if I set it to

``````if Input.is_action_just_pressed("player_jump"):
``````

- but then the player will jump only very low. How can I fix this? Should I use justpressed?

2. I need to set the maximum jump height after which the velocity.y will lerp to gravity pull. There will be tiles in the game that let the player jump higher (temporarily. How should I do that better?

Here's the code:

``````extends KinematicBody2D

var airborne
var movingright
var velocity = Vector2()
var walkspeed = 400
var gravityscale = 600
var jumpvelocity = 1300

movingright = true

func teleport_to(target_pos):
position = target_pos

func get_input():
if Input.is_action_pressed("ui_right"):
movingright = true
airborne = false
\$SnoozyAnim.play("walk")
velocity.x = walkspeed
elif Input.is_action_pressed("ui_left"):
movingright = false
airborne = false
\$SnoozyAnim.play("walk")
velocity.x = - walkspeed
else:
\$SnoozyAnim.play("idle")
airborne = false
velocity.x = lerp(velocity.x, 0, 0.2)

if not movingright:
\$SnoozyAnim.set_flip_h(false)
else:
\$SnoozyAnim.set_flip_h(true)

if Input.is_action_pressed("player_jump"):
velocity.y -= jumpvelocity
airborne = true
\$SnoozyAnim.play("jump")
\$JumpSound.play()

func _physics_process(delta):
velocity.y = gravityscale
get_input()
move_and_slide(velocity)
``````
in Engine
edited

I think its better to do one thing until you are confortable with the result and then start the next stuff. Try to do the character movement works well, then add the animations, e after that the sound. It becomes easier when you break all the game in small goals.

You need to declare where is the floor and what is the gravity. By doing it you can tell if the kinematic body is on ground or not. If it isnt you cant keep adding the velocity.y. And the gravity will start slowing the velocity.y force until it becomes positive and the body is atracted to the floor again.

``````extends KinematicBody2D

const FLOOR = Vector2(0, -1) #first you need to declare where the floor is in order to check if you are already jumping. the floor in 2d is Vector2(0, -1)
const GRAVITY = 10 #then you set a constant for gravity that you will add to your velocity.y, it will pull you KinematicBody2D back to the ground

var airborne
var movingright
var velocity = Vector2()
var walkspeed = 400
var gravityscale = 600
var jumpvelocity = 1300

movingright = true

func teleport_to(target_pos):
position = target_pos

func get_input():
if Input.is_action_pressed("ui_right"):
movingright = true
airborne = false
\$SnoozyAnim.play("walk")
velocity.x = walkspeed
elif Input.is_action_pressed("ui_left"):
movingright = false
airborne = false
\$SnoozyAnim.play("walk")
velocity.x = - walkspeed
else:
\$SnoozyAnim.play("idle")
airborne = false
velocity.x = lerp(velocity.x, 0, 0.2)

if not movingright:
\$SnoozyAnim.set_flip_h(false)
else:
\$SnoozyAnim.set_flip_h(true)

#if Input.is_action_pressed("player_jump"):
if Input.is_action_pressed("player_jump") && on_ground: #only jumps if you are on the floor
velocity.y -= jumpvelocity
on_ground = false #set that you arent on ground
airborne = true
\$SnoozyAnim.play("jump")
\$JumpSound.play()

func _physics_process(delta):

#func _physics._process(delta):
velocity.y += GRAVITY #here is where your gravity force pulls the kinematic body to the ground
get_input()
#move_and_slide(velocity)
velocity = move_and_slide(velocity, FLOOR)

if is_on_floor():   #here you are telling if you are on ground or jumping
on_ground = true
else:
on_ground = false
``````
by (16 points)

Thank you! It works, but the only parameter now it seems to react to is jumpvelocity, regardless of what I set gravityscale to. What I need is while he is airborne, I need it to fall faster, so that he doesn't hang in the air so long. I try different gravityscale but no difference. What am I missing?

Thank you again for your help!

Sorry, I missed that we now have GRAVITY const. Yes, it works.

One last question on that: later I want special tiles that serve as spring boards, to allow player jump higher. Do those tiles have to adjust jump height temporarily like a time loop?

I guess, I will have to make other nodes change Player's on_ground variable. Does that mean I have to export this variable in Player script?

you can make a different ground tile with a second collision shape above the ground so you can do something like that:

``````func _on_SpringBoard_body_entered(body): #when you enter the collision of the tile...
get_node("../Player").jumpvelocity += 500 #it will add 500 to the jump velocity in the Player script

func _on_SpringBoard_body_exited(body):  #when you exit it...
get_node("../Player").jumpvelocity = 1300 #it will set the jump velocity back to the original value
``````

this code will be inside the spring board script. you need to connect the spring board with itself in order to work.

Thanks!

The script now works, but for one animation.

The 'jump' animation is overrided all the time by 'walk', it never plays.

I try and try to make it work, I don't understand how to sort that override?

the problem in there is your right and left input code. You can solve this by only playing the walk animation when the player is on ground, like that:

``````if Input.is_action_pressed("ui_right"):
movingright = true
airborne = false
velocity.x = walkspeed
if on_ground:
\$SnoozyAnim.play("walk")

elif Input.is_action_pressed("ui_left"):
movingright = false
airborne = false
velocity.x = - walkspeed
if on_ground:
\$SnoozyAnim.play("walk")

else:
airborne = false
velocity.x = lerp(velocity.x, 0, 0.2)
if on_ground:
\$SnoozyAnim.play("idle")
``````