Search code examples
godotgdscript

Using move_and_collide and my CharacterBody2D is moving way too fast


I'm working on making Pong and I have two paddles on each side of the screen. Originally, I was using Input.get_vector() but that forced me to take in 4 arguments when I only need two. I also tried using Input.get_axis() but I was having trouble getting that to work.

Now I've went back to basics and started using Input.is_action_pressed() because it seemed less complicated and I ended the function with using move_and_collide() as I'll need the ball in the middle to bounce off the paddle and I don't think move_and_slide() would be best for that.

When I run the code it sort of works as intended but even with speed set to 1 the paddle goes incredibly fast. Also, the gravity is kind of wonky as even if I tap the up arrow just once, the paddle doesn't stop moving.

How can I fix my code so that the paddle doesn't zoom off screen and actually stops when I let go of the arrow key?

extends CharacterBody2D

var speed: int = 1

func _physics_process(delta):
    if Input.is_action_pressed("p2_up"):
        velocity.y -= speed
    elif Input.is_action_pressed("p2_down"):
        velocity.y += speed
    
    move_and_collide(velocity)

Solution

  • First, the units Godot 4 uses are metres and seconds. So, an speed of 1 is one metre per second.

    Second, _physics_process will run once every physics frame, which by default is 60 times per second.

    Third, Input.is_action_pressed returns true if the action is pressed, and false otherwise.

    Thus, here:

    extends CharacterBody2D
    
    var speed: int = 1
    
    func _physics_process(delta):
        if Input.is_action_pressed("p2_up"):
            velocity.y -= speed
        elif Input.is_action_pressed("p2_down"):
            velocity.y += speed
        
        move_and_collide(velocity)
    

    You are incrementing/decrementing the velocity by one second per metre per second, 60 times per second as long as you have the action pressed.

    So, in one second the character body goes from zero to 60 metres per second (134.2 miles per hour or 216 kilometers per hour).

    And you never reset the velocity.


    I believe you intended to set the velocity instead of incrementing/decrementing it:

    extends CharacterBody2D
    
    var speed: float = 1.0
    
    func _physics_process(delta:float) -> void:
        if Input.is_action_pressed("p2_up"):
            velocity.y = - speed
        elif Input.is_action_pressed("p2_down"):
            velocity.y = speed
        else:
            velocity.y = 0.0
        
        move_and_collide(velocity)
    

    If you wanted to support analog input you could use get_action_strength... But it is easier to use get_axis:

    extends CharacterBody2D
    
    var speed: float = 1.0
    
    func _physics_process(delta:float) -> void:
        velocity.y = Input.get_axis("p2_up", "p2_down")    
        move_and_collide(velocity)
    

    Using get_vector makes no sense here since it is only one axis.


    You say the gravity is wonky, but the code in question does not have gravity.

    You are responsible of the motion of the CharacterBody2D, and that includes implementing gravity.

    You can implement gravity and bounces yourself. However, if you want to create an object that other things can push, consider using RigidBody2D instead. If you do, Godot will handle gravity and bounces for you, and you would have to control it by adding forces and impulses instead.