I was following a tutorial for a script which makes a sprite follow another, the tutorial used Godot3.X whilst I use Godot 4. When it got to the point where I had to add move and slide to make the sprite able to move, it gave me errors.
extends CharacterBody2D
var speed = 200
var motion = Vector2.ZERO
const FLOOR_NORMAL: Vector2 = Vector2(0, -1)
var player = null
func _physics_process(delta):
motion = Vector2.ZERO
if player:
motion = position.direction_to(player.position) * speed
motion = move_and_slide(motion)
func _on_area_2d_body_entered(body):
print("entered")
player = body
func _on_area_2d_body_exited(body):
print ("exit")
player = null
This is the code that is giving the error (motion = move_and_slide(motion), is giving the error) This is intended to move a sprite towards the player. The move and slide allows it to move, or it should. My current assumption is that this is a Godot 4 problem but feel free to prove that assumption wrong. It says "Too many arguments for "move_and_slide()" call. Expected at most 0 but received 1." as the error. I hope someone has the answer.
What I describe in this answer applies to both CharacterBody2D
and CharacterBody3D
.
In Godot 4 the method move_and_slide
takes no arguments.
Instead, you set the properties of the CharacterBody2D
. In this case, instead of passing motion
, you would set the velocity
:
velocity = motion
move_and_slide()
motion = velocity
The intention is that you use velocity
directly, instead of declaring your own vector (which you called motion
). So remove motion
and use velocity
directly. Like this:
func _physics_process(delta):
velocity = Vector2.ZERO
if player:
velocity = position.direction_to(player.position) * speed
move_and_slide()
Note: As I explain below... Do not declare velocity
, the character body already has a velocity
property, you do not need to add one.
You might also want to set other properties. In particular the motion_mode
. Since you were not passing an UP vector, I assume you don't want the CharacterBody2D
to distinguish floor, walls, and ceiling, in which case you use the "Floating" motion mode. Otherwise, leave it on "Grounded". If you want to specify said UP vector, you find it in the up_direction
property.
I hope this section helps people searching for this problem.
In Godot 3 move_and_slide
did take multiple arguments. It was common to see calls such as move_and_slide(velocity)
or move_and_slide(velocity, Vector2.UP)
. If you find that in a tutorial, it is a Godot 3 tutorial, which is not what you want if you are working in Godot 4.
Of course in Godot 4 using that code results in the error "Too many arguments for "move_and_slide()" call. Expected at most 0 but received 1."
Here are some things might hint if if you are looking at a Godot 3 tutorial or a Godot 4 tutorial:
Godot 3:
onready
is a keyword.
The 3D Node class is called Spatial
.
The characters in 3D are made with KinematicBody
, and in 2D with KinematicBody2D
.
They might declare velocity
or a similar variable.
move_and_slide
returns a velocity, and takes a velocity as first parameter among other things. So code looks like this:
velocity = move_and_slide(velocity, Vector3.UP)
Godot 4:
@onready
is an annotation.Node3D
.CharacterBody3D
, and in 2D with CharacterBody2D
.velocity
or similar variable, instead they just use the built-in velocity
property.move_and_slide
takes no parameter, returns if there was a collision (bool
) and works with the properties of the CharacterBody3D
/CharacterBody2D
(such as velocity
and up_direction
). So code looks like this:move_and_slide()
I've adapted this list from an answer in the game development sister site (link).
So you got some Godot 3 code that you want to translate to Godot 4, and there is a call to move_and_slide
where they pass a velocity, and perhaps some other arguments. What to do?
First of all, you do not need to declare velocity
. Your CharacterBody2D
/CharacterBody3D
already have a velocity
property, so set that.
i.e. instead of this:
move_and_slide(something)
You want to do this:
velocity = something
move_and_slide()
Don't do the following (in the following example we are shadowing the velocity
property with our own velocity
variable, which won't work as expected):
var velocity = something # <- DON'T DO THIS
move_and_slide()
In the above examples something
refers to whatever computation you had there. For example if you had something like this:
move_and_slide(direction * speed)
Then now you do this
velocity = direction * speed
move_and_slide()
I hope that makes sense.
Perhaps you had code that looked more like this:
move_and_slide(something, some_up_vector)
Then you do this:
velocity = something
up_direction = some_up_vector
move_and_slide()
For a more concrete example, that might look like this:
velocity = direction * speed
up_direction = Vector3.UP
move_and_slide()
Of course, for 2D that woudl be Vector2.UP
instead of Vector3.UP
.
Note: for up_direction
to work, you also want motion_mode
to be set to MOTION_MODE_GROUNDED
(which you can set from the inspector). The up_direction
is used in conjunction with floor_max_angle
to discriminate if the body is on the floor, a wall, or ceiling.
I hope the pattern is clear: what you passed as arguments to move_and_slide
are now properties you set before calling it (that could be setting them in the inspector, right before the call, or whenever it is appropiate).
Here is the complete list (in order): velocity
, up_direction
, stop_on_slope
, (there is no equivalent for the max_slides
parameter), floor_max_angle
, (there is no equivalent for the infinite_inertia
parameter, in general it is no longer necessary).
On the return value of move_and_slide
:
About the return value: In Godot 3 move_and_slide
used to return the final velocity
. Now it updates the velocity
property, so you can read it after calling move_and_slide
. However, if you are working with the velocity
property chances are that you do not need to. And as stated before, In Godot 4 move_and_slide
returns a bool
, which tells you if there was any collision (including slides).