Godot: Normalize two vectors on a Vector3

Created on 11 Jun 2019  路  8Comments  路  Source: godotengine/godot

I suggest to add the ability to normalize only two vectors on a Vector3 to be able to separate the gravity and jump of a KinematicBody from the direction.
The normalize would take three arguments all set to true by default.

To normalize the direction without the y gravity it would look like this:

if Input.is_action_pressed("ui_up"):
    velocity += -global_transform.basis.z * speed
if Input.is_action_pressed("ui_down"):
    velocity += global_transform.basis.z * speed
if Input.is_action_pressed("ui_left"):
    velocity += -global_transform.basis.x * speed
if Input.is_action_pressed("ui_right"):
    velocity += global_transform.basis.x * speed

velocity.y -= GRAVITY # Gravity
velocity = velocity.normalized(true, false, true)
archived discussion feature proposal core

Most helpful comment

I don't understand this issue. How do you normalize that way? Normalizing a vector is basically keeping the direction but changing the magnitude to 1 (the length) You can't skip one coordinate because you need all of them to get the normalized vector. Sorry but what you are asking isn't a normalized vector and it makes little sense.

The example doesn't make any sense either. You are adding the speed but then you "normalize" it removing the speed multiplication? why? I really don't understand what you are trying to do.

All 8 comments

I don't understand this issue. How do you normalize that way? Normalizing a vector is basically keeping the direction but changing the magnitude to 1 (the length) You can't skip one coordinate because you need all of them to get the normalized vector. Sorry but what you are asking isn't a normalized vector and it makes little sense.

The example doesn't make any sense either. You are adding the speed but then you "normalize" it removing the speed multiplication? why? I really don't understand what you are trying to do.

Would you mind doing it like, Vector2(vel.x, vel.z).normalized()

It doesn't make sense indeed, you can't "normalize" a vector with only two components. If what you want is a normalized vector to which the gravity is later added, you can do:

if Input.is_action_pressed("ui_up"):
    velocity += -global_transform.basis.z * speed
if Input.is_action_pressed("ui_down"):
    velocity += global_transform.basis.z * speed
if Input.is_action_pressed("ui_left"):
    velocity += -global_transform.basis.x * speed
if Input.is_action_pressed("ui_right"):
    velocity += global_transform.basis.x * speed

velocity = velocity.normalized()
velocity.y -= GRAVITY # Gravity

But BTW, normalizing the speed also doesn't really make sense. What you have to normalize is the directional vector, to which you would then apply a speed factor or gravity.

Would you mind doing it like, Vector2(vel.x, vel.z).normalized()

Agree with swarnimarun, can already be done longhand. The question is whether it would be something you would realistically do often enough to warrant a specific function?

On the other hand you could argue the same for all Vector2 functions on components of Vector3. A better solution for all this would be to have a way of accessing 2 components of a Vector3 as a Vector2, thus allowing all the Vector2 functions to be called.

You might be able to have it access components something like this:
velocity.xz() = velocity.xz().normalized()
for a more generalized method. I use something like this in my c++ vector templates.

If what you want is a normalized vector to which the gravity is later added

I have added the gravity after normalizing the Vector3 and the gravity gets normalized too I don't know why (falling slowly and linearly and slower when moving), this is why I have added this suggestion.

This script doesn't work:

extends KinematicBody

const GRAVITY = 0.15

var velocity = Vector3()
var speed = 6
var max_falling_speed = 20
var jump_height = 4

var mouse_sensitivity = 0.15

func _ready():
    Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

# ----------------------------------
# Keyboard controls and gravity

func _physics_process(delta):
    velocity.x = 0 # Resets the direction when no key is pressed
    velocity.z = 0

    if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
        if Input.is_action_pressed("ui_up"):
            velocity += -global_transform.basis.z * speed
        if Input.is_action_pressed("ui_down"):
            velocity += global_transform.basis.z * speed
        if Input.is_action_pressed("ui_left"):
            velocity += -global_transform.basis.x * speed
        if Input.is_action_pressed("ui_right"):
            velocity += global_transform.basis.x * speed

        if Input.is_action_just_pressed("ui_accept") and is_on_floor():
            velocity.y = jump_height

        velocity = velocity.normalized()

        velocity.y -= GRAVITY # Gravity
        velocity.y = clamp(velocity.y, -max_falling_speed, max_falling_speed)

    if Input.is_action_just_pressed("ui_cancel"):
        get_tree().quit()

    velocity = move_and_slide(velocity, Vector3.UP, true)

# ----------------------------------
# Mouse controls

func _input(event): 
    if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
        rotate_y(deg2rad(-event.relative.x * mouse_sensitivity)) #yaw
        $Camera.rotate_x(deg2rad(-event.relative.y * mouse_sensitivity)) #pitch
        $Camera.rotation.x = clamp($Camera.rotation.x, deg2rad(-90), deg2rad(90))

velocity.xz() = velocity.xz().normalized()

Good idea but it would require a method for each combination possible.

In that above example, you are definitely normalizing your gravity. Since this runs every physics tick the gravity you applied last tick is normalized along with your input. On top of which you then apply gravity. So your gravity over time wont actually be growing here.

The reason you fall a little faster when you're not moving is because your gravity is the only thing affecting the vector and so when it's normalized it becomes Vector3(0, -1, 0). And then you are removing 0.15 making your maximum total gravity -1.15 That is the largest it can ever be. Hopefully that makes sense, I'm pretty new to this.

I would suggest separating your input out and only normalizing that. * it by speed, add it to your velocity and remove gravity.

But this is all off topic sorry. I believe once you understand the problem you're having here you may change your mind about this feature request.

You can just do this:

var horizontal = Vector2(velocity.x, velocity.z)
horizontal = horizontal.normalized()
velocity.x = horizontal.x
velocity.z = horizontal.y

Or just keep track of horizontal velocity separately (only determined by input and normalization) and then set velocity's horizontal components from scratch each time.

Closing due to lack of support (see the above comments).

Was this page helpful?
0 / 5 - 0 ratings