godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.41k stars 21.06k forks source link

range_lerp gives odd values #25926

Open Shadowblitz16 opened 5 years ago

Shadowblitz16 commented 5 years ago

Godot version: 3.0.6 Windows 7 Home 64 bit

it seems like I am getting odd values out of range_lerp that prints as -1.#IND

I feel that this is because I am passing unordered min and max and passing and values below min and max. however these things should not matter and passing values to lerp functions should be unclamped and scale depending on the order of the min and max values and their ranges.

here is a sample script on the issue.

extends Area2D

export(Texture) var texture_00_degrees
export(Texture) var texture_22_degrees
export(Texture) var texture_45_degrees
export(Texture) var texture_67_degrees

export(float)  var move_fric   = 0
export(float)  var move_speed  = 0
export(float)  var move_accelF = 0
export(float)  var move_decelB = 0

export(float)  var turn_fric  =  0
export(float)  var turn_speed  = 0
export(float)  var turn_accelL = 0
export(float)  var turn_accelR = 0

var move_velocity = Vector2(0, 0)
var turn_velocity = 0;

var screen_size
var screen_buffer = 8;

func _ready():
    screen_size = get_viewport().size

func _process(delta):
    var move_dir = Vector2(0,-1).rotated(rotation)
    var slow_dir = Vector2(0, 0)

    move_velocity  = real_lerp(move_velocity, slow_dir, move_fric)
    if (Input.is_action_pressed("ui_up"   )): move_velocity = real_lerp(move_velocity, move_dir, move_accelF)
    if (Input.is_action_pressed("ui_down" )): move_velocity = real_lerp(move_velocity, slow_dir, move_decelB)
    update_velocity(delta)

    turn_velocity = real_lerp(turn_velocity, 0, turn_fric)
    if (Input.is_action_pressed("ui_left" )): turn_velocity = real_lerp(turn_velocity, -1, turn_accelL)
    if (Input.is_action_pressed("ui_right")): turn_velocity = real_lerp(turn_velocity, +1, turn_accelR)
    update_rotation(delta)

func update_velocity(delta):

    #print(move_velocity)
    position  += move_velocity * move_speed * delta * 30
    position.x = wrapf(position.x, -screen_buffer, screen_size.x + screen_buffer)
    position.y = wrapf(position.y, -screen_buffer, screen_size.y + screen_buffer)

func update_rotation(delta):
    #print(turn_velocity)
    rotation_degrees += turn_velocity * turn_speed * delta * 30

    #var angle     = wrapf(rotation_degrees, 0.0, 360.0)
    #var angle_spr = floor(fmod(angle, 90.0) / 22.5)

    #print(angle)

    #if   (angle_spr == 0): $sprite.texture = texture_00_degrees
    #elif (angle_spr == 1): $sprite.texture = texture_22_degrees
    #elif (angle_spr == 2): $sprite.texture = texture_45_degrees
    #elif (angle_spr == 3): $sprite.texture = texture_67_degrees
    #$sprite.rotation = floor(angle / 90) * 90;

func real_lerp(min_value, max_value, by):

    print(min_value)
    if   (typeof(min_value) == TYPE_VECTOR2 && typeof(max_value) == TYPE_VECTOR2):  
        var value_x = real_lerp(min_value.x, min_value.x, by);
        var value_y = real_lerp(max_value.y, max_value.y, by);
        print("value { "+str(value_x)+", "+str(value_y)+"}");
        return Vector2(value_x, value_y);

    elif (typeof(min_value) == TYPE_VECTOR2 && typeof(max_value) == TYPE_REAL): 
        var value_x = real_lerp(min_value.x, max_value, by);
        var value_y = real_lerp(min_value.y, max_value, by);
        return Vector2(value_x, value_y);

    else:   
        var value   = range_lerp(by, 0, max_value-min_value, min_value, max_value);
        return value;
akien-mga commented 5 years ago

It would be nice to have a shorter, to the point script or project. The code pasted does a lot more than range_lerp, and we don't have the values assigned to your export variables to try it (nor your scene).

Shadowblitz16 commented 5 years ago

I can try to get a better script

Shadowblitz16 commented 5 years ago

ok here is a more compact script.. attach it to a area2D

extends Area2D

var move_velocity = Vector2(0,0)
const move_fric   = 2
const move_speed  = 2
const move_accelF = 2
const move_decelB = 2

func _process(delta):

    var move_dir = Vector2(0,-1).rotated(rotation)
    var slow_dir = Vector2(0, 0)

    move_velocity  = real_lerp(move_velocity, slow_dir, move_fric)
    if (Input.is_action_pressed("ui_up"   )): move_velocity = real_lerp(move_velocity, move_dir, move_accelF)
    if (Input.is_action_pressed("ui_down" )): move_velocity = real_lerp(move_velocity, slow_dir, move_decelB)
    print("{"+str(move_velocity.x)+", "+str(move_velocity.y)+"}")

func real_lerp(min_value, max_value, by):

    if   (typeof(min_value) == TYPE_VECTOR2 && typeof(max_value) == TYPE_VECTOR2):
        var value_x = real_lerp(min_value.x, min_value.x, by);
        var value_y = real_lerp(max_value.y, max_value.y, by);
        return Vector2(value_x, value_y);

    elif (typeof(min_value) == TYPE_VECTOR2 && typeof(max_value) == TYPE_REAL):
        var value_x = real_lerp(min_value.x, max_value, by);
        var value_y = real_lerp(min_value.y, max_value, by);
        return Vector2(value_x, value_y);

    else:
        var value   = range_lerp(by, 0, max_value-min_value, min_value, max_value);
        return value;
ghost commented 5 years ago

Value from range_lerp is undefined if range size == 0 (istart == istop or ostart == ostop) (https://github.com/godotengine/godot/pull/10225#issuecomment-321735458)

var value   = range_lerp(by, 0, max_value-min_value, min_value, max_value);

Converting to constants (for first iteration) gives:

var value   = range_lerp(2, 0, 0-0, 0, 0);
akien-mga commented 4 years ago

I guess this simply needs to be documented.