Mink’s Godot Greif - Busted Jump

Godot Version

Godot Version 3.5

Question

Last time I was here I lamented a problem I was having with adding with adding climbing and the scene crashing. I have fixed the issue with the scene crashing and I found a work around with the player clipping into the sky. The issue I’m having now is with the jump, or more accurately, lack there of. The current issue is that the player stays stuck to the floor when I try to jump, as seen here;
video of the problem
As the video shows, neither the jump nor the climb works.

Here is the code for you to check.

extends KinematicBody

#exports
export var max_speed = 10
export var acceleration = 70
export var friction = 30
export var air_friction = 10
export var gravity:float= -0.0
export var jump_impulse = 20
export var mouse_sensitivity = .1
export var controller_sensitivity = 3
export var rot_speed = 25
export var climb_speed = 3.0

const GRAVITY:      float = -40.0
const JUMP_IMPULSE: float =  01.0

var gravity_active: bool  = true
var angular_velocity = 15

#Vectors
var velocity = Vector3.ZERO
var snap_vector = Vector3.ZERO
var direction = Vector3()
var gravity_vec = Vector3()
var movement = Vector3()

#onready vars
onready var spring_arm = $SpringArm
onready var pivot = $Pivot
onready var mesh = $Pivot/skin

#climbing
onready var still_on_wall_check := $Wall_check/still_on_wall_check
onready var wall_check := $Wall_check/wall_check
onready var stick_point_holder = $Stick_point_holder
onready var stick_point = $Stick_point_holder/Stick_point
var is_climbing = false

#mouse
func _ready():
	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func _unhandled_input(event):
	if event.is_action_pressed("click"):
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	
	if event.is_action_pressed("toggel_mouse_captured"):
		if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
			Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
		else:
			Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
			
	if event is InputEventMouseMotion and Input.get_mouse_mode() ==Input.MOUSE_MODE_CAPTURED:
		rotate_y(deg2rad(-event.relative.x * mouse_sensitivity))
		spring_arm.rotate_x(deg2rad(-event.relative.y * mouse_sensitivity))
			
func _check_vel_y(VEL_Y: float, debug: String) -> void:
	if VEL_Y != velocity.y:
		print("Velocity Y Changed %f -> %f at: %s" % [VEL_Y, velocity.y, debug])
		VEL_Y = velocity.y

func _physics_process(delta):
	var VEL_Y = velocity.y
	var input_vector = get_input_vector()
	_check_vel_y(VEL_Y, "get_input_vector()")
	var direction = get_direction(input_vector)
	_check_vel_y(VEL_Y, "get_direction()")
	apply_movement(input_vector, direction, delta)
	_check_vel_y(VEL_Y, "apply_movement()")
	apply_friction(direction, delta)
	_check_vel_y(VEL_Y, "apply_friction()")
	apply_gravity(delta)
	_check_vel_y(VEL_Y, "apply_gravity()")
	update_snap_vector()
	_check_vel_y(VEL_Y, "update_snap_vector()")
	jump()
	_check_vel_y(VEL_Y, "jump()")
	climbing()
	_check_vel_y(VEL_Y, "climbing()")
	apply_controller_rotation()
	_check_vel_y(VEL_Y, "apply_controller_rotation()")
	spring_arm.rotation.x = clamp(spring_arm.rotation.x, deg2rad(-65), deg2rad(25))
	_check_vel_y(VEL_Y, "clamp(spring_arm)")
	velocity = move_and_slide_with_snap(velocity, snap_vector, Vector3.UP, true)
	_check_vel_y(VEL_Y, "move_and_slide_with_snap()")
	
	
#inputs
func get_input_vector():
	var input_vector = Vector3.ZERO
	input_vector.x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
	input_vector.z = Input.get_action_strength("move_backwards") - Input.get_action_strength("move_forward")
	return input_vector.normalized() if input_vector.length() > 1 else input_vector

func get_direction(input_vector):
	var direction = (input_vector.x * transform.basis.x) + (input_vector.z * transform.basis.z)
	return direction
	
#movement, friction, & gravity
func apply_movement(input_vector, direction, delta):
	if direction != Vector3.ZERO:
		velocity.x = velocity.move_toward(direction*max_speed,acceleration*delta).x
		velocity.z = velocity.move_toward(direction*max_speed,acceleration*delta).z
#		pivot.look_at(global_transform.origin + direction, Vector3.UP)
		pivot.rotation.y = lerp_angle(pivot.rotation.y, atan2(-input_vector.x, -input_vector.z), rot_speed * delta)
		
func apply_friction(direction, delta):
	if direction == Vector3.ZERO:
		if is_on_floor():
			velocity = velocity.move_toward(Vector3.ZERO, friction * delta)
		else:
			velocity.x = velocity.move_toward(direction*max_speed,air_friction*delta).x
			velocity.z = velocity.move_toward(direction*max_speed,air_friction*delta).z

func apply_gravity(delta: float) -> void:
	if gravity_active:
		velocity.y = clamp(velocity.y + (delta * GRAVITY), GRAVITY, JUMP_IMPULSE)

#snap to floor
func update_snap_vector():
	snap_vector = -get_floor_normal() if is_on_floor() else Vector3.ZERO

#jumping
func jump():
	if Input.is_action_just_pressed("jump") and is_on_floor():
		snap_vector = Vector3.ZERO
		velocity.y = jump_impulse
	if Input.is_action_just_released("jump") and velocity.y > jump_impulse /2:
		velocity.y = jump_impulse / 2

#climbing
func climbing() -> void:
	#check if player is able to climb
	if wall_check.is_colliding():
		if still_on_wall_check.is_colliding():
			if Input.is_action_just_pressed("jump"):
				if is_on_floor():
					is_climbing  = false
				else:
					is_climbing = true
			else:
				is_climbing = false
		else:
			#if player is at top of a climb, boost them over the top
			jump()
			yield(get_tree().create_timer(0.3), "timeout")
			is_climbing = false
	is_climbing = false
	
	if is_climbing:
		#if player is climbing disable gravity
		gravity_active = false
		max_speed = climb_speed
		direction = Vector3.ZERO
		gravity_vec = Vector3.ZERO
		
		#sticks player to the wall
		stick_point_holder.global_transform.origin = wall_check.get_collision_point()
		self.global_transform.origin.x = stick_point.global_transform.origin.x
		self.global_transform.origin.z = stick_point.global_transform.origin.z
		
		#move player relative to the walls normal
		var rot = -(atan2(wall_check.get_collision_normal().z, wall_check.get_collision_normal().x) - PI/2)
		var f_input = Input.get_action_strength("forward") - Input.get_action_strength("back")
		var h_input = Input.get_action_strength("right") - Input.get_action_strength("left")
		direction = Vector3(h_input, f_input, 0).rotated(Vector3.UP, rot).normalized() 
	else:
		gravity_active = true
		
func _process(delta):
	#turns body in the direction of movement
	if direction != Vector3.ZERO and !is_climbing:
		mesh.rotation.y = lerp_angle(mesh.rotation.y, atan2(-direction.x, -direction.z), angular_velocity * delta)
	elif direction != Vector3.ZERO and is_climbing:
		mesh.rotation.y = -(atan2(wall_check.get_collision_normal().z, wall_check.get_collision_normal().x) - PI/2)

#controller 
func apply_controller_rotation():
	var axis_vector = Vector2.ZERO
	axis_vector.x = Input.get_action_strength("look_right") - Input.get_action_strength("look_left")
	axis_vector.y = Input.get_action_strength("look_down") - Input.get_action_strength("look_up")
	
	if InputEventJoypadMotion:
		rotate_y(deg2rad(-axis_vector.x) * controller_sensitivity)
		spring_arm.rotate_x(deg2rad(-axis_vector.y) * controller_sensitivity)

For your climbing, this part inside func climbing() could be the issue:

			if Input.is_action_just_pressed("jump"):
				if is_on_floor():
					is_climbing  = false
				else:
					is_climbing = true
			else:
				is_climbing = false

is_action_just_pressed() is only true in the moment when you start pressing the button. One physics tick later, the else statement will set is_climbing to false again. I don’t think that’s how it’s supposed to be?

And shortly after that, you’re changing some variables:

	if is_climbing:
		#if player is climbing disable gravity
		gravity_active = false
		max_speed = climb_speed
		direction = Vector3.ZERO
		gravity_vec = Vector3.ZERO

max_speed and gravity_vec never seem to get reverted to their original values afterwards. (Doesn’t seem to matter for gravity_vec yet, but for max_speed it looks like a problem.)

About the jumping: Have you tried to put a print statement directly after velocity.y = jump_impulse inside func jump() (while disabling the other prints)? Or to use move_and_slide() instead of move_and_slide_with_snap() inside your _physics_process()? (At least to narrow down where this issue is caused.)

hmmm, maybe i could try changing the

if Input.is_action_just_pressed("jump"):

to

if Input.is_action_just_pressed("climb"):

and have them both set to same key, but then it would be a matter of making sure that climb only applies to certain walls so that it doesn’t try to jump and climb at the same time. as for the print function, I kind of hate using it because i cant really decipher it, but I can try it I suppose

I wasn’t taking about the button you use, but how you change your is_climbing bool. (And I just realised, there’s one more line where it will cause problems.)

func climbing() -> void:
	#check if player is able to climb
	if wall_check.is_colliding():
		if still_on_wall_check.is_colliding():
			if Input.is_action_just_pressed("jump"):
				if is_on_floor():
					is_climbing  = false
				else:
					is_climbing = true
			else:
				is_climbing = false
		else:
			#if player is at top of a climb, boost them over the top
			jump()
			yield(get_tree().create_timer(0.3), "timeout")
			is_climbing = false
	is_climbing = false

The middle else: will set is_climbing to false while both rays are still colliding, which doesn’t seem to be intended.
And no matter what happens during the if statements, the last line will set it to false anyway. (Probably a missing else: there?)

Instead of a print statement you could also add a breakpoint or something, it’s just about checking if the line of code that applies the jump_impulse is ever reached (and what’s the velocity.y value afterwards).

so how would i fix that? I’m not all that versed in coding.

Can’t say if that’s everything that needs to be changed here, but you definitely should delete the middle else statement, then put an else before the last is_climbing = false:

func climbing() -> void:
	#check if player is able to climb
	if wall_check.is_colliding():
		if still_on_wall_check.is_colliding():
			if Input.is_action_just_pressed("jump"):
				if is_on_floor():
					is_climbing  = false
				else:
					is_climbing = true
		else:
			#if player is at top of a climb, boost them over the top
			jump()
			yield(get_tree().create_timer(0.3), "timeout")
			is_climbing = false
	else:
		is_climbing = false

the player is still stuck to the floor when i try to jump. maybe it would help if there were more people giving input.

Have you tried these things yet? There’s only so much other people can do without having some more information.

@hyvernox is right; the logic in climbing() isn’t going to work as-is.

Additionally, is_climbing is always going to be false. Your code:

#[...]
#climbing
func climbing() -> void:
	#check if player is able to climb
	if wall_check.is_colliding():
		if still_on_wall_check.is_colliding():
			if Input.is_action_just_pressed("jump"):
				if is_on_floor():
					is_climbing  = false
				else:
					is_climbing = true
			else:
				is_climbing = false
		else:
			#if player is at top of a climb, boost them over the top
			jump()
			yield(get_tree().create_timer(0.3), "timeout")
			is_climbing = false
	is_climbing = false
	
	if is_climbing:
#[...]

Look at the last two lines. You’re unconditionally setting is_climbing to false after all the stuff above trying to set it. Execution will never get in to your if is_climbing: test.

so do i just remove those last two lines?

how would i go about fixing the climbing logic?

The last line I quoted was the beginning of the test that potentially disables gravity and does all the wall sticking stuff. You don’t want to take that out, I don’t think.

The second last line that just sets is_climbing = false is breaking things, though, I think that line should be deleted.

What’s the difference between wall_check and still_on_wall_check?

ok i deleted the second to last line but the player is still stuck ton the floor. as for wall_check and still_on_wall_check, still_on_wall_check checks if the player in still on the wall, I got it from this tutorial.

Maybe scatter some print() statements in there to see what’s actually happening.

BRO I SUCK ASS AT PRINTING :sob: :sob: :sob:

Most skill issues can be resolved with practice and effort.

Fixing the climbing won’t repair the jump. And for testing the climbing, I guess the jump needs to be done first.

For prints, I’d recommend adding one inside jump():

func jump():
	if Input.is_action_just_pressed("jump") and is_on_floor():
		snap_vector = Vector3.ZERO
		velocity.y = jump_impulse
		print(velocity)

and disabling the others by making them a comment (adding the #):

func _check_vel_y(VEL_Y: float, debug: String) -> void:
	if VEL_Y != velocity.y:
		#print("Velocity Y Changed %f -> %f at: %s" % [VEL_Y, velocity.y, debug])
		VEL_Y = velocity.y

Then test the game and tell us if you’re ever getting any prints or not. (Every time you press the jump button while being on the floor should print one line.)

ok this is what the console gave me

--- Debugging process started ---
Godot Engine v3.5.stable.official.991bb6ac7 - https://godotengine.org
OpenGL ES 3.0 Renderer: NVIDIA GeForce RTX 4060/PCIe/SSE2
Async. shader compilation: OFF
 
(0, 20, 0)
(0, 20, 0)
(0, 20, 0)
(-1.570685, 20, -1.96196)
(0, 20, 0)
(0, 20, 0)
(0, 20, 0)
(-3.460056, 20, 0.729066)
(-0.762395, 20, -2.586075)
(-2.181092, 20, 0.939524)
(-0.999644, 20, 0.626675)
(0.206979, 20, 3.973421)
(0, 20, 0)
(-10.653819, 20, -1.568783)
(0, 20, 0)
(-6.704904, 20, -2.166196)
(0, 20, 0)
(0, 20, 0)
(0, 20, 0)
(0, 20, 0)
(8.167699, 20, -2.905265)
(0, 20, 0)
--- Debugging process stopped ---

(Ignore this post. Read the follow-up instead.)

Okay, so the jump_impulse is getting applied. The print inside jump() can be removed then.

Next I would check if using move_and_slide makes a difference and if the velocity.y is still correct when reaching it. At the end of _physics_process(), make the move_and_slide_with_snap() line a comment to disable it for now and add the other lines below:

	#velocity = move_and_slide_with_snap(velocity, snap_vector, Vector3.UP, true)
	if velocity.y > 0.0:
		print(velocity.y)
	velocity = move_and_slide(velocity, Vector3.UP, true)

This should print decreasing values for a short time after pressing the jump button.

So, I have looked through your code once more and found one serious issue:

const JUMP_IMPULSE: float =  01.0
func apply_gravity(delta: float) -> void:
	if gravity_active:
		velocity.y = clamp(velocity.y + (delta * GRAVITY), GRAVITY, JUMP_IMPULSE)

You’re using 1.0 as maximum value for clamping velocity.y . Setting JUMP_IMPULSE to 20.0 should fix it.