Why does the velocity property work like this?

Godot Version

4.3

Question

This is more curiosity than actually looking for help, but I wouldn’t know where else to put this. I’ve been using Godot and learning how to program for about a week, just finished making my first game on my own (an extremely simple 2D maze) and I’m curious about something in the code. The main part of my player character code is this:

func _process(delta):
var velocity = Vector2.ZERO
if Input.is_action_pressed(“go_right”):
velocity.x += 1
if Input.is_action_pressed(“go_left”):
velocity.x -= 1
if Input.is_action_pressed(“go_down”):
velocity.y += 1
if Input.is_action_pressed(“go_up”):
velocity.y -= 1

if velocity.length() > 0:
velocity = velocity * speed

position += velocity * delta
move_and_slide()

Mostly retyped from the documentation’s “first 2D game tutorial”. It gave me the error “The local variable “velocity” is shadowing an already-declared property at the base class “CharacterBody2D”.” Which I understand, and makes sense, it’s not a problem both because of how small my project was and the fact that I could just rename the variable. But I was curious, so I tried both removing the “var” before velocity and also deleting the first line of _process entirely. For some reason, using the pre-existing velocity property makes the player go a lot faster, and deleting the first line makes it go so fast it completely disappears off the screen, even going through walls.

…So I just want to understand why??? Why do all those things behave differently? Isn’t the velocity property the same as Vector2.ZERO anyway??

Well firstly, velocity and speed are measuring the same thing. One is a vector so it is a speed with a direction, the other is a scalar, so it is just value with no direction.

The velocity * speed you are doing here should really be direction * speed, which is what velocity is. The inbuilt velocity also includes gravity and accelerations.

The CharacterBody2D already has a property called velocity, hence your error when you declared it again a variable. (Which you pointed out anyway).

Then you are updating the position manually with velocity, and then calling move and slide, again updating the position in pixels per second. But, you are calling it in _process, which is not the same as _physics_process. The latter is called at a fixed rate to preserve physical behaviour, the former happens as fast a possible but can vary due to process time, hence the variable frame rate. Move and Slide should be called in physics_process.

Deleting the first line means your velocity gets 1 added to it, then it is multiplied by speed. Then another 1 gets added to it, then it is again multiplied by speed, etc etc. And in your small project, this might be happening at least 60 times a second. Hence the rapid acceleration, making it jump any walls you might have in place so there is no time for it to be detected.

When you shadowed the property with the var value, your move_and_slide was probably set to 0 and stayed at 0. Your position statement then moved it slowly across the screen. When you unshadowed it, you were doing it twice with position and move and slide, when you removed it your acceleration was enormous as described previously.

Hope that helps.

3 Likes

As a short explanation, in Godot 4, the velocity is built-in parameter of Characterbody2D so you did not need to define it. You did not need to change position, just set the velocity and use the code move_and_slide to move. And if you are doing this by docs, then make sure you are watching the latest version docs.

Here is an example that shows how to move a character:

func _physics_process(delta):
    var direction = Input.get_vector("go_left", "go_right", "go_up", "go_down")
    velocity = direction * speed
    move_and_slide()

This is the correct version of your movement codes.