Trying to make a simple 2D movement script, yet it does not work if the code is in a function that is called in the physics process

Godot Version

4.2.2.stable

Question

I would like to know why the following code does not work if I have the code that handles movement in its own function and then call it in the physics process function, moving the code out of the movement function and into the physics process works but I would like to know why my version of the code does not work.

extends CharacterBody2D

@export var stats : PlayerStats

var input : Vector2

func _physics_process(delta):
	
	_movement(velocity, input, delta)
	


func _get_input():
	return Input.get_vector("left", "right", "up", "down").normalized()

func _movement(velocity, input, delta):
	
	input = _get_input()
	
	if input == Vector2.ZERO:
		if velocity.length() > (stats.friction * delta):
			velocity -= velocity.normalized() * (stats.friction * delta)
		else:
			velocity = Vector2.ZERO
	elif input != Vector2.ZERO:
		velocity += (input * stats.accel * delta)
		velocity = velocity.limit_length(stats.max_speed)
	
	move_and_slide()

func _movement(velocity, input, delta):

This function declares it’s own velocity, we call this “Shadowing” as the previous velocity from CharacterBody2D is now inaccesable. For clarity let’s re-write this function without using pre-existing variable names

extends CharacterBody2D

@export var stats : PlayerStats

var input : Vector2

func _physics_process(delta):
	
	_movement(velocity, input, delta)
	


func _get_input():
	return Input.get_vector("left", "right", "up", "down").normalized()

func _movement(vfoo, ifoo, dfoo):
	
	ifoo = _get_input()
	
	if ifoo == Vector2.ZERO:
		if vfoo.length() > (stats.friction * dfoo):
			vfoo -= vfoo.normalized() * (stats.friction * dfoo)
		else:
			vfoo = Vector2.ZERO
	elif ifoo != Vector2.ZERO:
		vfoo += (ifoo * stats.accel * dfoo)
		vfoo = vfoo.limit_length(stats.max_speed)
	
	move_and_slide()

In this version we see that the real velocity is never changed, only the function’s copy of velocity.

The easiest solution to your problem is to declare movement without velocity or input as arguments, this will use the CharacterBody2D’s definitions instead.

extends CharacterBody2D

@export var stats : PlayerStats

var input : Vector2

func _physics_process(delta):
	_movement(delta)


func _get_input():
	return Input.get_vector("left", "right", "up", "down") # don't normalize this

func _movement(delta: float) -> void:
	input = _get_input()
	
	if input == Vector2.ZERO:
		if velocity.length() > (stats.friction * delta):
			velocity -= velocity.normalized() * (stats.friction * delta)
		else:
			velocity = Vector2.ZERO
	elif input != Vector2.ZERO:
		velocity += (input * stats.accel * delta)
		velocity = velocity.limit_length(stats.max_speed)
	
	move_and_slide()
1 Like

Thank you very much! This is a really good explanation and I will keep this in mind from now on!

Shadowing is evil! There is a warning for shadowed varibles so look out for those :warning:

1 Like