Ok, I'm beginning to notice that all my lerps are wrong and actually don't work like they should (over a set period of time). And I don't find a straight answer. So in my current problem, I have a variable scale_looking, which changes depending on how fast the car is driving. So lets say it's 30. This is the amount I want my camera to rotate (either left or right) from looking straight. And I want this over a period of time, let's say 3 seconds (also need it go back). I thought lerp would to this... but lerp just gives a value back only once, if I now understand correctly. So how do I actually set things up so that I have a startvalue (ex. 0), and endvalue (ex. 30) and have it gradually change from start to end over time (ex. 3 sec.

Currently I have this working, but the change is abrupt:

func get_input(delta):
	look_around = Input.get_action_strength("turn_left") - Input.get_action_strength("turn_right")
	var scale_looking = follow_this.fwd_mpsf / 3
	follow_this.get_node("HUD").test_state(scale_looking)
	if (look_around < -0.95 or look_around > 0.95):
		rotate_object_local(Vector3.UP, lerp(0, scale_looking * look_around, delta))

Here is the current effect:

So I'm aware I'm doing it wrong, but since I'm going to need it several times more, I want to know how it is approached the right way.

Cheers.

On the Q&A and reddit they also said normally you would use a Tween in such cases, but apparently not advised in my case.

But as I'm looking around fixing all these "problems", I've noticed part of my solutions have been "band-aiding", kinda cheating my way to an effect instead of what I was aiming at, because of a lack of mathematical skills. Bit unrelated to the original post (although, it all needs to happen gradually). Because most of my conditions for anything is based on the speed of the car, basically: changing camFOV from 70 gradually to 85 relative to the speed of 150km/h to 200km/h (fov 100 in case of boost 250 km/h) changing steer_limit from 0.6 gradually to 0.2 to the speed of 0km/h to 200 km/h) (and maybe again in case of boost) * changing the height and distance of the cam relative to the speed (to compensate for the FOV.

And since most of the functions have weight values from 0 to 1... I probably need to find something (mathematical) that says: I want something to happen with this property/variable, starting from this startspeed with a startvalue of ... (so weightvalue 0) to this endspeed with endvalue ... (weightvalue 1).

That's also kinda where that looking left/right is based on. The more speed the car has, the more it looks to the left or the right (only if the joystick is completely to the left/right [and I'm also probably going to implement that it needs to be held more than a second (or 2) ]. Only exception is that the looking left/right doesn't always need to happen, like it does with changing the FOV or the height and distance.

Wish I was better at math :/ I don't even know how you call such a calculation. In case of 150km/h to 200km/h, that's a 0.25 difference ... and that 0.25 is 1 in the weightvalue of 0 to 1 (in which most things in Godot happens). But still... damn... I know the logic, but for the life of me can't find the solution. Anyway... =) Seems I have my "melding down" moment :o :)

You can do something like this:

var speed_scale = (current_speed - min_speed) / (max_speed - min_speed)
var cam_fov = min_fov + speed_scale * (max_fov - min_fov)

More generally, this would be called a linear interpolation or lerp. See here for more details. http://codetuto.com/2017/02/7-lerping-tricks-need-know-game-developer/

I think I almost got what I need, just need to get it in the right syntax.

So I know I need to create a function that takes 5 parameters: min_speed, max_speed, current_speed, min_val, max_val. This function should return one value and that is immediatly the value of the variable or property. So if I take my example of speed vs FOV, I have min_speed = 150, max_speed 200. The difference between them (diff_speed) equals 50. Let's say the current_speed is 170. So to know how much percent 170 is in that diff_speed, I do (current_speed - min_speed) / diff_speed. So 170 - 150 = 20, that divided by 50, gives me 0.4 or 40% of the difference speed. That's taken care of that part... I hope.

So, having that 0.4, I now can jump over to convert it over to my FOV change (or other change, like the steering_limit). So from FOV 70 to 85. Going by that same formula and the data that I have: max_val - min_val is 85 - 70 = 15, which is the diff_value. So I have my diff_value, I have my percentage where my speed is at, relative to the difference between values. That means x / diff_value = 0.4 . That makes the formula x = 0.4 * 15 = 6. This result I need to add to my min_value, so that makes it 76, which is the value I'm looking for to pass back to the variable/property I want to change in relation to the speed. Right?! So the FOV should be 76 when the car is driving 170 km/h

So all this I need to write into a function. And probably also some if statement to make sure it only works between the values I've given.

Ok,... damn, that hurt. But can anyone confirm if my thoughtprocess is right. Did I finally solve it?

Cheers.

@cybereality said: You can do something like this:

var speed_scale = (current_speed - min_speed) / (max_speed - min_speed)
var cam_fov = min_fov + speed_scale * (max_fov - min_fov)

More generally, this would be called a linear interpolation or lerp. See here for more details. http://codetuto.com/2017/02/7-lerping-tricks-need-know-game-developer/

Oh, you already posted an answer... So this is what lerp already does? But doesn't lerp() only take 3 parameters? Going to check that tomorrow, since it's already deep into the night over here and I already didn't sleep last night. This was already keeping me awake again. :#

Still not sleeping... still putting it into perspective. That link I have come across several times. Some I understood and some went past my head at that time (some things still do).

But now I do indeed see the lerp in my step by step process and your answer. With the difference that regarding the speed, the lerp() function asks me something I don't have and actually want to have (the speed_scale or weight) and gives me something I already have (the current_speed). So in that way, I can't use lerp() I guess. But for your 2nd line, I can use lerp() right? So I could use var cam_fov = lerp( min_fov, max_fov, speed_scale ) ? And I don't need any delta or any kind of transition/tweening (for the camera point to the left/right I probably still do). God I hope so, because that would mean I'm finally beginning to understand (that part atleast).

@eyeEmotion said: But for your 2nd line, I can use lerp() right? So I could use var cam_fov = lerp( min_fov, max_fov, speed_scale ) ? God I hope so, because that would mean I'm finally beginning to understand (that part atleast).

Lerp will return a value interpolated from the minimum value (the first argument) to the maximum value (the second argument) where the level of interpolation is based on the final argument, which generally is in the range of 0 to 1, where 0 will return the minimum value, 1 will return the maximum value, and 0.5 will return the value in between.

Looking at the video, and if I understand the issue correctly, you might need to do something like the following:

# This needs to be a class variable! In other words, it has to be defined
# outside of the functions
var lerp_strength = 0
var is_lerping = false
var current_fov
# other code here. We'll assume the code below is in a function
# first, calculate the FOV we want to have
# (I'm not sure how you need to calculate this, or if what I wrote below will work)
var desired_fov = min_fov + (current_speed / min_speed)
# then, we need to detect if the FOV change is large enough to warrant a change
if (is_lerping == false):
	if (abs(desired_fov - current_fov) > 5):
		# begin changing the FOV!
		is_lerping = true
		current_fov = $Camera.fov
if (is_lerping == true):
	lerp_strength += delta
	var new_camera_fov = lerp(current_fov, desired_fov, lerp_strength)
	if (lerp_strength >= 1):
		is_lerping = false
		current_fov = new_camera_fov
	# apply new_camera_fov to the camera
	$Camera.fov = new_camera_fov

That said, it's late where I'm at and I almost certainly over complicated it. :sweat_smile:

If speed_scale is the range of 0 to 1, then you can probably skip everything I wrote above and just use the code you showed initially: var cam_fov = lerp( min_fov, max_fov, speed_scale ). The big thing is that speed_scale needs to be in the range of 0 to 1, where it is 0 when the vehicle is not moving fast enough to change the FOV, and where it is 1 when the vehicle is at the maximum speed.

The "t" value is the weight, a number typically between 0 and 1, that will blend between the first value (min value) and the second value (max value). I called it "speed_scale" but you can call it anything you want, maybe "t_fov" would make more sense. "0" means you return the first value and "1" means you return the second value, and a number in-between will be that much of a percent between the two. So all you need is the min and max value for the parameter you want to set, and also the percentage of the blending (or interpolation) that you want to use.

At first the lerp still jumped from one to the other and not gradually. Then I realized my fwd_mps was int(fwd_mpsf). But apparantly the weight isn't only from 0 to 1, only the portion between from and to value. At first I thought it was strange I had an FOV of 25, while nowhere in my code I had assigned such a value. Then I noticed that it was because the scaling was -3. If FOV 70 was at 120km/h, then at 0km/h it was 25. Since with boosting the car goes over the max_speed, the FOV automatically also goes beyond my max_FOV. I also did have to address sudden drops in speed because of driving against something that stopped me, otherwise the FOV kept going smaller.

func _physics_process(delta):
	...
	var current_speed = follow_this.fwd_mpsf
	min_speed = 120
	max_speed = 200

	speed_scale = (current_speed - min_speed) / (max_speed - min_speed)

	if (current_speed > min_speed):
		set_fov(lerp(min_FOV, max_FOV, speed_scale))
		target_distance = lerp(min_cam_distance, max_cam_distance, speed_scale)
		target_height = lerp(min_cam_height, max_cam_height, speed_scale)
	elif (get_fov() > min_FOV or (follow_this.handbrake and get_fov() > min_FOV)):
		set_fov(get_fov() - delta * 7)
		target_distance = lerp(target_distance, 4.0, spdChangeFOV)
		target_height = lerp(target_height, 1.0, spdChangeFOV)

So at last this works as I initially wanted it to. Funny how trying to find a solution for one thing happens to give the solution for something else. There is one "beauty" error I get with this. Since I have an if-statement to not go over a certain speed, at the end, when accelerate is pressed, it constantly jumps from 199 to 200... this is also slightly visible in the FOV. Tried to make the FOV integers, but that only made the transition jittery. I also used the code of the FOV for the engin_force. since I'm still not able to figure out how to remove the drag from driving uphill or turning. So I just give a high value engine_force at the lower speeds and gradually turn it down, so if I want to drive uphill from a standstill, it has the force to do so.

So still one thing to figure out is how to rotate the camera looking left or right only when the joystick is held down to either fully left or right (= -1 or 1) for 2 or 3 seconds. I noticed doing the rotating based on the speed of the car is useless. I just need to rotate it on a given angle and transition it smoothly of a set time. And go smoothly back to the 0 rotation if the joystick is released. Currently I have:

func get_input(delta):
	if (!keyb):
		look_around = Input.get_action_strength("turn_left") - Input.get_action_strength("turn_right")
		var scale_looking = follow_this.fwd_mpsf / 3
		if (abs(look_around) == 1.0):
			rotate_object_local(Vector3.UP, lerp(0, scale_looking * look_around, delta)) 

The scale_looking is useless here, I think. Probably need to use a tween here? Or is it possible with a Timer/time, that maybe also can check if the joystick is held more than x amount of seconds? I also saw something about lerp_angle in the Help, but that code gives strange results. After that, It's time to upload a new video about the progress.

You can't compare floating point numbers for equality. Because of the way computers store the float numbers it will almost never be equal to an exact number like that. What you think is "1.0" in the computer will actually be "1.00000003" or something like that. Instead, either check that it is above or below a specific number or check that the absolute value of the difference is less than something small. For example.

if (abs(look_around - 1.0) < 0.0001):

@cybereality said: You can't compare floating point numbers for equality. Because of the way computers store the float numbers it will almost never be equal to an exact number like that. What you think is "1.0" in the computer will actually be "1.00000003" or something like that. Instead, either check that it is above or below a specific number or check that the absolute value of the difference is less than something small. For example.

if (abs(look_around - 1.0) < 0.0001):

Oh ok. I did notice that with other values aswell... as I always get a different value. For example, my min_fov is 70, but it always ends up being 69 and some "random" number behind. So as a general advice it's best to avoid equals to for conditions, when it's with values. It does work though, but maybe because the joystick has a value between 0 and 1?

Would if (abs(look_around) > 0.99) : work too?

Actually funny to spend this much time on the camera controls and effects, yet the next for me regarding this game is modeling the inside of the car and implement VR ?. But then again, I want people to be able to play it flat and VR.

For the "stress" the coding is giving me the last few weeks (because I didn't maintain my skills in that very well), it does make it worthwhile when it finally works and I realize how much I missed programming.

Also, the coding bit about changing things in relation to the speed. I tried it on my steering_limit, but that doesn't work and actually has an opposite effect. Since the VehicleBody slows down the car when turning (or driving uphill), the steering limit would expand again and thus make the car able to turn more. But more turning is more slowing down, is again expanding the steering_limit. So actually it's a way of slowing the car down even faster than the VehicleBody itself does. So for now I'll have to stick to the harsh limitations with if/elif statements.

3 years later