Search Unity

Set-Rate Lerping (Resolved)

Discussion in 'Scripting' started by DangerSnoot, Jan 31, 2010.

  1. DangerSnoot

    DangerSnoot

    Joined:
    Nov 23, 2009
    Posts:
    213
    As part of a movement script I've created a set of speeds at which the player can move. These are the target speeds, however for the actual speed I would like a more gradual transition between each other, or between being stopped and these values, to create a gradual accelleration or decelleration. This doesn't seem too hard, and I can interpolate between values easily enough, except that I want a set rate of increase and decrease which does not depend upon the distance between values. The reason for this is that you currently accellerate more rapidy when going from say, stopped to sprinting, then you do when going from stopped to walking. Does that kinda make sense? Well regardless, I'm sure the solution is actually quite simple, but it's got me stumped all the same. Any help would be greatly appreciated!
     
  2. AmazingRuss

    AmazingRuss

    Joined:
    May 25, 2008
    Posts:
    933
    I'm not totally sure I understand what you're saying, but give this a try:

    v = Mathf.Lerp(v, targetValue, Time.deltaTime * speed);

    in your update loop.

    It starts out moving fast, then eases up to the target value.
     
  3. DangerSnoot

    DangerSnoot

    Joined:
    Nov 23, 2009
    Posts:
    213
    Thanks for having a stab at it, but that's not quite what I'm after. It's my fault for not wording it very well.

    Hang on, I'll try again, this time with a little example.

    The first three variables represent the speeds that different gaits produce.

    var playerWalkSpeed = 3;
    var playerRunSpeed = 10;
    var playerSprintSpeed = 15;

    var playerTargetSpeed;

    Whichever one you're trying to do will turn the variable playerTargetSpeed into it. So when you press the 'run' button playerTargetSpeed becomes 10.

    And then there's the actual speed the player's moving at.

    var playerActualSpeed;

    I want this to keep trying to equal playerTargetSpeed, but normal lerping doesn't seem up to it for the following reason.

    playerActualSpeed = Mathf.Lerp(playerActualSpeed, playerTargetSpeed, 1);

    If you're going from stopped to walking using the above lerping code, it will take 1 second for your speed to change from 0 to 3 (a 3m/s accelleration). However if you're going from stopped to running it will take 1 second to go from 0 to 10 (a 10m/s accelleration).

    As you can see this means that a player can accellerate to a walking pace much quicker if they tell the character to run, but then tell it to stop when the walking speed is already reached, than if they just pressed walk.

    What I need is for all accellerations and decellerations to be at a set pace instead.

    Does that make any more sense?
    Anyhoo, thanks again for the reply!
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Actually that code will make your actual speed instantly equal to the target speed. The third parameter in lerp is a float from 0 to 1, with 0 returning the first parameter and 1 returning the second parameter. If it's .5, then it returns a value halfway between the first and second parameters. So you need to lerp from 0 to 1 over a period of time, depending on the distance between the first two parameters.

    --Eric
     
  5. DangerSnoot

    DangerSnoot

    Joined:
    Nov 23, 2009
    Posts:
    213
    Goddammit, I'm being an idiot again. Well, thanks for clearing that one up. I'd been putting lower values than 1 into mine previously so the issue wasn't as obvious back then.

    In that case I don't think lerping is really the best solution any more then. I'll just use if statements and have it add or subtract conventionally using Time.deltaTime.

    But yeah, much appreciated as always.
     
  6. tool55

    tool55

    Joined:
    Jul 10, 2009
    Posts:
    334
    I'm fairly new to scripting myself, but it seems like Lerp should work. You need to put Time.deltaTime as the last parameter instead of a fixed integer. You're accelerating over time.

    Then, if you divide Time.deltaTime by the difference between the actual speed and the target speed you can slow the acceleration proportionally. You'll probably want to take the absolute value of that number so that you're not dividing by a negative number.

    Code (csharp):
    1.  
    2. var smoothaccelerate = Mathf.Abs(TargetSpeed - ActualSpeed);
    3.  
    4. Mathf.Lerp(ActualSpeed, TargetSpeed, Time.deltaTime/smoothaccelerate);
    Like I said,I'm not great at this either, but perhaps some variation of this will work. :roll:
     
  7. DangerSnoot

    DangerSnoot

    Joined:
    Nov 23, 2009
    Posts:
    213
    That's exactly what I was after! Thanks tool55!

    You know, I'd actually fixed the problem by using if statements and just adding or subtracting using Time.deltaTime depending on whether or not the difference was above or below the target speed. But then I got landed with this annoying vibration thing going on when actual speed hit the target speed, so I sorted that one out by identifying whether the values were rising or falling, calculating which keys were being pressed and had recently been pressed and then locking values to the target speed when it came within a buffer zone based on that.

    It took 120 lines of code to do and was a complete nightmare. Then you solve the issue in 2 lines. Haha, classic. I think I know which one I'll be using now though.
     
  8. tool55

    tool55

    Joined:
    Jul 10, 2009
    Posts:
    334
    Glad it helps. I've been trying to keep my code really simple because I'm not good at this yet. I still get lost when I look at some of the scripts by the pros. You figure it out bit by bit I guess.

    Anyway, I got to thinking about what I wrote to you. If you find that it doesn't work well,it might be because you need a proportion instead of simply subtracting one speed from another.

    Code (csharp):
    1. var smoothaccelerate: float =Mathf.Abs( (TargetSpeed - ActualSpeed)/15);
    I'm assuming that 15 is your maximum speed. In this case, you multiply smoothaccelerate times Time.deltaTime instead of dividing. Besides my coding, my math is bad, too. Anyway, see what happens. :D
     
  9. DangerSnoot

    DangerSnoot

    Joined:
    Nov 23, 2009
    Posts:
    213
    That really did help. The concept's so simple that it makes it really easy to fine tune and integrate with other stuff too!