Search code examples
godotgdscript

Godot 4 is giving me the error of too many arguments in move_and_slide()


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.


Solution

  • 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.


    Pick Godot 4 tutorials

    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.
    • The 3D Node class is called Node3D.
    • The characters in 3D are made with CharacterBody3D, and in 2D with CharacterBody2D.
    • They do not declare 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).


    Adapting Godot 3 code to Godot 4

    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).