- Home /
Answer provided was correct but not an answer to the original question, so searching for this subject will not find useful information here.
How to control easing in Mathf.smoothDamp?
Hi guys
I'm using smoothDamp to move between amounts of acceleration and braking on a vehicle. It's my first game and I've not used smoothDamp before so I'm hoping someone can explain how I might influence the easing in and out of the transition between values.
Here is my current code (just the relevant bits):
float accelerate; // Calls Axis for right trigger
float accelerationFactor = 0.0f;
float currentSpeed = 0.0f;
float maxSpeed = 300.0f;
void FixedUpdate ()
{
// Basic movement
accelerate = Input.GetAxisRaw ("Fire2");
float newSpeed = Mathf.SmoothDamp(currentSpeed, maxSpeed * accelerate, ref accelerationFactor, 0.4f);
currentSpeed = newSpeed;
// Forward movement
rb.AddForce (transform.forward * currentSpeed);
I've read through the Unity documentation I could find on this and several tutorials or explanatory articles but I'm unclear on what exactly I need to adjust or add to control the easing.
I'm also not entirely clear on what the difference between the Velocity and SmoothTime variables are doing. I think the SmoothTime is controlling how quickly the old value updates to the new value and that Velocity is exposing the change in the values each frame (please someone correct me if I'm wrong) but I can't work out how I might use these to change how the changes happen.
Any help much appreciated.
Answer by Harinezumi · May 25, 2018 at 09:37 AM
I think that's not how you use SmoothDamp()
(and I'm not sure you should use it for this purpose). SmoothDamp()
is function similar to Mathf.Lerp()
, which returns a value between start and end point, but it incorporates smoothing approach over a given time.
To better understand what it does, let's go through each parameter, using the names given on the scirpting reference page:
- current
: the starting point of the value (so the name is wrong, it should be start). In your case, starting acceleration
- target
: the end point of the value. In your case it should be a desired acceleration value
- currentVelocity
: this is an output parameter to provide you with the rate of change. In your case, it would be give you the rate of acceleration
- smoothTime
: the time over which the value should go from current
to target
. By default, this is actual game time
- maxSpeed
: you can limit the maximum rate of change, but by default it isn't limited
- deltaTime
: how much time passed since last call. It is used with smoothTime
. By default, it is Time.deltaTime
So this is for when you want a value (for example, speed) to change from a starting value to a target value over the time specified by smoothTime
. To use it correctly, you usually want to leave current
the same value, otherwise the calculation will be off.
In your case, you would need to provide it the starting acceleration, the desired acceleration, and the time you want that change to happen, then keep calling with the same values during that time (and it would calculate the rate of acceleration for you).
As you can see, this is not good for reacting to immediate changes, such as user input. Instead, you could either use the actual well-known physics calculation (velocity = acceleration x time, location = velocity x time), or - as you are using rigidbodies - accelerate by adding a force in the forward direction (remember, acceleration = force / mass). In this second case (if you are not in vacuum) you would need to add a decelerating force as well to make your vehicle slow down when not accelerating.
However, maybe I did not understand what you want to achieve, in which case, please explain, and I'll update my answer.
BTW, don't handle input in FixedUpdate()
, because it is not called every frame, so the reaction will be laggy. Get the input in Update()
, and store the input value to be used in FixedUpdate()
.
Hi and thanks for the response @Harinezumi,
Using your suggestion, how would you control the rate at which the change in force happens? To begin with I had rb.AddForce (transform.forward * maxSpeed * User Input %)
, with "user input %" co$$anonymous$$g from the axis value of a controller trigger (0 - 1).
The initial issue was that when the user releases the trigger the "user input %" immediately drops to Zero (0) so no force was being added and the rb quickly came to a stop. To mimic coasting in real life (where a vehicle gradually loses speed over time when the accelerator is released) I used SmoothDamp()
to control how quickly the force fell to zero. I've also implemented the same for acceleration and braking by having a different smoothTime
value for each state.
Very happy to use an alternative to SmoothDamp()
if you think there is a better way. Can you explain how I can achieve the same result using your suggested method?
Also, thanks for letting me know what should go in FixedUpdate()
and what belongs in Update()
. I'm never sure what should go where. $$anonymous$$y understanding is that physics calculations are best done in FixedUpdate()
?
rb.AddForce()
by default applies a force to the object, which will generate an acceleration, which will modify the velocity. That is, it doesn't limit the velocity at all, and depending the circumstances your vehicle can become infinitely fast. You would either need to directly limit rb.velocity
(not recommended), or calculate the force that can be applied based on current speed (better).
The above approach is not bad, but maxSpeed
is actually not maximum speed, but maximum accelerating force. You could limit speed for example as float maxApplicableForce = maxForce * $$anonymous$$athf.$$anonymous$$ax(0, (maxSpeed - rb.velocity.magnitude));
and use maxApplicableForce
in rb.AddForce()
. This is not the best approach though, it should rather be an inverse exponential decrease approaching maximum speed.
I am not sure why the vehicle came to a stop quickly, but it is possibly due to friction. Try creating a physics material (an asset similar to a render material) with very low friction (<0.1), and assigning it to the collider.
Regarding update functions, you use Update()
for logic and rendering updates, FixedUpdate()
to modify physics (like applying forces to rigidbodies or moving them with physics), and LateUpdate()
for updates that need to take effect after everything has moved. So you can do a physics calculation somewhere else, but you should only apply it in FixedUpdate()
.
Follow this Question
Related Questions
C# script not working 1 Answer
AddForce has no effect on my cannonball. 3 Answers
Realistic player movement? 2 Answers
Problem with when turning left with angling and the force of the projectile 1 Answer