How to stop player floating when they are supposed to be falling?

Godot Version

4.3

Question

so the movement code works as intended when i jump but when i walk off a ledge i just float in the air. heres the code: `extends CharacterBody3D

var current_direction = “none”
var speed = 16
var health = max_health
const max_health = 80
var ammo = 8
const JUMP_VELOCITY = 4.5
var gravity = 9.8
const SENSITIVITY = 0.01
var weaponselect = [“0”,“1”]
var selectedweapon = 0
var is_selection_pistol = selectedweapon == 0 and current_direction == “forward”
var playerid = RandomNumberGenerator.new()
@onready var head = $Head
@onready var camera = $Head/PLayerCamera
@onready var healthbar = $Control/Healthbar
@onready var healthbar_text = $Control/Health_number
@onready var ammobar = $Control/Ammobar
@onready var animation_tree = $AnimationTree
@onready var Pistol = $Head/c_skeleton/Skeleton3D/BoneAttachment3D12/soldier_morphs_low
@onready var animation = $AnimationPlayer
signal damaged(by)

func _ready():
var id = playerid.randi_range(000000000, 999999999)
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
print(id)
Pistol.visible = true

func select_weapon(selectedweapon):
if selectedweapon == 0:
$secondary_select.value = 0
$primary_select.value = 1
if selectedweapon == 1:
$secondary_select.value = 1
$primary_select.value = 0
Pistol.visible = is_selection_pistol
var is_selection_pistol = selectedweapon == 0 and current_direction == “forward”
animation_tree.set(“parameters/Add2/add_amount”,float(is_selection_pistol))

func _process(delta):
healthbar.value = health
healthbar_text.text = str(health)
if Input.is_action_just_released(“p_fire”):
pass
ammobar.value = ammo
if Input.is_action_just_released(“p_fire”) and selectedweapon == 0:
if ammo > 0:
ammo -= 1
if ammo == 0:
ammo -= 0
animation.play(“canary_reload”)
$MouseIconReady.visible = false
$MouseIconReload.visible = true
await get_tree().create_timer(2).timeout
ammo += 8
$MouseIconReady.visible = true
$MouseIconReload.visible = false

if Input.is_action_just_pressed("select_up"):
	selectedweapon = abs((selectedweapon - 1) % weaponselect.size())
	select_weapon(selectedweapon) 
if Input.is_action_just_pressed("select_down"):
	selectedweapon = abs((selectedweapon + 1) % weaponselect.size())
	select_weapon(selectedweapon)

func _unhandled_input(event):
if event is InputEventMouseMotion:
head.rotate_y(-event.relative.x * SENSITIVITY)
camera.rotate_x(-event.relative.y * SENSITIVITY)
camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-40), deg_to_rad(60))

func _physics_process(delta):
# Add the gravity.
if not is_on_floor():
velocity.y -= gravity * delta
if velocity.y > 0:
current_direction = “up”
elif velocity.y < 0:
velocity.y = 0

# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
	velocity.y = JUMP_VELOCITY
var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_backward")
var direction = (head.global_transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()

if is_on_floor():
	
	if direction:
		velocity.x = direction.x * speed
		velocity.z = direction.z * speed
	else:
		velocity.x = 0
		velocity.z = 0
else:
	velocity.x = lerp(velocity.x, direction.x * speed, delta * 2.0)
	velocity.z = lerp(velocity.z, direction.z * speed, delta * 2.0)

move_and_slide()

player_movement()

func player_movement():
if velocity.y < 0:
current_direction = “down”
if Input.is_action_pressed(“move_right”):
play_animation(1)
current_direction = “right”
elif Input.is_action_pressed(“move_left”):
play_animation(1)
current_direction = “left”
elif Input.is_action_pressed(“move_backward”):
play_animation(1)
current_direction = “backward”
elif Input.is_action_pressed(“move_forward”):
play_animation(1)
current_direction = “forward”
else:
play_animation(0)
velocity.x = 0
velocity.y = 0

func play_animation(movement):

if current_direction == "right":
	if movement == 1:
		animation.play("canary_swalk")
	elif movement == 0:
		animation.play("canary_idle_001")

if  current_direction == "left":
	if movement == 1:
		animation.play_backwards("canary_swalk")
	elif movement == 0:
		animation.play("canary_idle_001")

if  current_direction == "forward":
	if movement == 1:
		animation.play("canary_fwalk")
	elif movement == 0:
		animation.play("canary_idle_001")

if  current_direction == "backward":
	if movement == 1:
		animation.play_backwards("canary_fwalk")
	elif movement == 0:
		animation.play("canary_idle_001")

if  current_direction == "up":
	animation.play("canary_fall")

if  current_direction == "down":
	animation.play("canary_fall")

if  current_direction == "down" and $raycast_down.is_colliding():
	animation.play_backwards("canary_fall")`

If you wrap your code block with a line with three backticks (```) above and below, it will format properly in the forum.

I assume (you can print every frame to verify…) that is_on_floor() is staying true even when you walk off a ledge and hover? If so, you might check whether the physics system has been told where the floor is and isn’t…

i did that and it printed the values as it should

You’re multiplying gravity by delta.
Do this:
velocity -= mass (can be any number, really) * gravity * delta
so it’s not feather-like. It appears like floating, but that’s because the number is so low (approx 0.156 applied) it doesn’t even register to your eye as movement.

I don’t think you are correct. 9.8 is the default gravity vector. It should work fine unless dboi59436 (the question asker) has really big objects in the scene.

anyway i think this is the issue

if velocity.y > 0:
    current_direction = “up”
elif velocity.y < 0:
    velocity.y = 0

the velocity.y value will never be less than 0 (going down) because you are setting it to 0 if it’s less than 0.

Perhaps.
But in my case, multiplying gravity (float) by delta has made it feathery.
Also yes, that statement there would definitely make gravity not work.