Search Unity

adding acceleration or easing to transform forward

Discussion in 'Scripting' started by Hubardo, Jul 28, 2015.

  1. Hubardo

    Hubardo

    Joined:
    Apr 2, 2015
    Posts:
    22
    got a simple 3 intervals forward engine script

    i want it to accelerate between each interval instead of instantly changing to the next speed level
    how would i go about it with the existing code?

    heres the script

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ForwardAccel : MonoBehaviour
    5. {
    6.     private float baseSpeed = 5.0f;
    7.     int enginePower;
    8.  
    9.  
    10.     // Use this for initialization
    11.     void Start ()
    12.     {
    13.         enginePower = 0;
    14.     }
    15.    
    16.     // Update is called once per frame
    17.     void Update ()
    18.     {
    19.         if (Input.GetButtonDown("Vertical") && Input.GetAxisRaw("Vertical") > 0)
    20.         {
    21.             if (enginePower < 3)
    22.             {
    23.                 enginePower = enginePower + 1;
    24.             }
    25.         }
    26.  
    27.     transform.position += transform.forward * enginePower * baseSpeed * Time.deltaTime;
    28.  
    29.     }
    30. }
    31.  
     
  2. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    You could build a delay into the update which would essentially log the time (Time.time) that the change in power occurs. Then, you'd put in a conditional that says the enginePower can only increase if(Time.Time >= lastChangeTime + 3f) or something. If you want to make it so that the power can be changed at any time, but that change can't be FELT until a certain timer has passed, separate out the input from the change like this:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ForwardAccel : MonoBehaviour
    5. {
    6.    private float baseSpeed = 5.0f;
    7.    private float gearChangeDelay;
    8.    private float lastPowerChange;
    9.    private int curPower;
    10.    private int desiredPower;
    11.  
    12.    void Start ()
    13.    {
    14.         gearChangeDelay = 3f;
    15.         lastPowerChange = Time.time - 5f;
    16.         desiredPower = 0;
    17.         curPower = 0;
    18.    }
    19.  
    20.    void Update ()
    21.    {
    22.        if (Input.GetButtonDown("Vertical"))
    23.        {
    24.            int direction = 1;
    25.            if(Input.GetAxisRaw("Vertical") < 0)
    26.                 direction = -1;
    27.  
    28.            int newPower = desiredPower + direction;
    29.            if (newPower >= 0 && newPower <= 2)
    30.            {
    31.                 desiredPower = newPower;
    32.            }
    33.        }
    34.  
    35.        if(desiredPower != curPower && Time.time >= lastPowerChange + gearChangeDelay)
    36.        {
    37.            lastPowerChange = Time.time;
    38.  
    39.            if(desiredPower > curPower)
    40.                curPower += 1;
    41.            else
    42.                curPower -= 1;
    43.         }
    44.         transform.position += transform.forward * curPower * baseSpeed * Time.deltaTime;
    45.    }
    46. }
    Something like that?
     
  3. Hubardo

    Hubardo

    Joined:
    Apr 2, 2015
    Posts:
    22
    hi Lysander
    thanks for the help but im either missing something or you misunderstood me
    all this did as far as i can tell is add an input delay in the transitions between the first to second and second to third power levels
    i was looking for a way to accelerate between power levels, so instead of going 1 to 2, it will go 1 to 1.1 to 1.2 etc..

    also im a total beginner so i would like to understand my script for learning purposes and not just copy/paste, and your modified script is fairly different then mine
     
  4. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    I see, I misunderstood the problem indeed, in spectacular fashion!

    In order to set a smaller interval, just make enginePower into a float instead of an integer (floats can handle floating-point values, in other words decimal points). Once you've done that, you can change the "enginePower = enginePower +1;" to increase by .1, or less, instead.

    You'll have to change the integers you're assigning to the enginePower variable to be floats instead as well, in C# at least. You can do this by just adding an "f" to the end of the numbers. For instance, 0f instead of 0, .1f instead of .1, etc...
     
  5. Hubardo

    Hubardo

    Joined:
    Apr 2, 2015
    Posts:
    22
    :)

    i tried floats before, but its not exactly what im after.
    i DO want the power to increase by 1 every time the button is pressed, just not at once

    lets say im at 0 power and i press the forward button, now im at 1 power but i want the object to have a period of time it is accelerating to the current level, and the same if i press the button three times in a row, now im at 3 power, but my object should slowly accelerate from 0 to 3
     
  6. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    I know you said you didn't want to copy/paste, but this is some fairly complicated logic, so forgive me but I'm going to post (commented, this time) one method for doing what you want. I really couldn't come up with a way to explain this that wasn't going to be horribly confusing, so:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ForwardAccel : MonoBehaviour
    5. {
    6.     private float baseSpeed = 5.0f;          //mutliplier for total speed
    7.     private float curPower = 0f;                //the power we have
    8.     private int desiredPower = 0;             //the power we want
    9.     private float changeIncrement = 1f;   //multiplier for how fast to adjust speed changes
    10.  
    11.     void Update()
    12.     {
    13.         //if we're pressing up or down
    14.         if (Input.GetButtonDown("Vertical"))
    15.         {
    16.             //default direction is positive (up)
    17.             int direction = 1;
    18.  
    19.             //if we're pressing down instead, flip it to negative
    20.             if (Input.GetAxisRaw("Vertical") < 0)
    21.                 direction = -1;
    22.  
    23.             //add the change (based on direction) to the old power value, temporarily
    24.             int newPower = desiredPower + direction;
    25.  
    26.             //if we're within a set bounds (0 to 2), make the change "real"
    27.             if (newPower >= 0 && newPower <= 2)
    28.             {
    29.                 desiredPower = newPower;
    30.             }
    31.         }
    32.  
    33.         //we modify the increment by the time the last frame took to process
    34.         //this makes the change smoother using real-time
    35.         float adjustedIncrement = changeIncrement * Time.deltaTime;
    36.  
    37.         //if the power we want is more than the power we have
    38.         if (curPower <= desiredPower - adjustedIncrement)
    39.         {
    40.             curPower += adjustedIncrement;
    41.         }
    42.         //if the power we want is less than the power we have
    43.         else if (curPower >= desiredPower + adjustedIncrement)
    44.         {
    45.             curPower -= adjustedIncrement;
    46.         }
    47.         else
    48.         {
    49.             //match the desired speed exactly
    50.             curPower = desiredPower;
    51.         }
    52.  
    53.         transform.position += transform.forward * curPower * baseSpeed * Time.deltaTime;
    54.     }
    55. }
     
  7. Hubardo

    Hubardo

    Joined:
    Apr 2, 2015
    Posts:
    22
    thanks a bunch, this is very helpful, the comments are awsome

    i admit i expected a much simpler addition to my code, and hopefully something i could easily implement in other parts of my script, but ill get there first
    it sorta accomplishes what im after
    but ill have to take some time breaking it down and understanding it, will post if i need any more advice on this matter
     
  8. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    The relevant process (slowly adjusting to match a goal number) only relies on 3 parts: a starting point (the current value), an ending point (the goal value), and an increment. Keeping that in mind, and using those 3 things as parameters, you can make a new function and just copy the entire part of the script in update that deals with slowly adjusting time over into that function, then just change the names to match some parameter names, like so:
    Code (csharp):
    1. public float IncrementValue(float current, float goal, float increment)
    2. {
    3.     float adjustedIncrement = increment * Time.deltaTime;
    4.  
    5.     if (current <= goal- adjustedIncrement)
    6.     {
    7.         current += adjustedIncrement;
    8.     }
    9.     else if (current >= goal + adjustedIncrement)
    10.     {
    11.         current -= adjustedIncrement;
    12.     }
    13.     else
    14.     {
    15.         current = goal;
    16.     }
    17.     return current;
    18. }
    This would then be re-usable in your code elsewhere if needed. You can also look at Lerp and MoveTowards and SmoothStep and SmoothDamp, now that you see more or less how they work.
     
  9. Hubardo

    Hubardo

    Joined:
    Apr 2, 2015
    Posts:
    22
    @Lysander
    hi again :)

    so, i was messing around with this script a little further, added rotation based on my speed and such
    now i have a problem and im not sure where it originates
    basically, all is working as intended for now, the faster i go the slower i rotate, while the fastest rotation speed is at power level 1 and dropping as it goes from 1 to 3, so besides while being stationarey, at power 3 it turns the slowest .
    the problem is that once i get to power level 3 and then decelerate, my rotation speed no longer acts as it should, its subtle but noticeable, if i go from 3 to 1 and back to 3 then my turn speed would be faster than it should.
    any ideas what i am missing? tried debuging some of the values and i cant find the culprit
    if anyone beside Lysander has a clue it would be welcome as well

    here is the complete script (forgive the unoptimized mess, still learning :))

    **EDIT** found the little bugger :) it was caused by my reverse state, once i pressed down it was set to true and stayed true even after pressing up

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerController : MonoBehaviour
    5. {
    6.     public float baseSpeed = 1.0f;                //mutliplier for total speed
    7.     private float currentPower = 0f;               //the power we have
    8.     private int desiredPower = 0;                  //the power we want
    9.     private float changeIncrement = 0.5f;          //multiplier for how fast to adjust speed changes
    10.     public float rotationSpeed = 50.0F;
    11.     private float stationaryRotationSpeed = 10.0f;
    12.     private bool reverseState = false;
    13.  
    14.     // Use this for initialization
    15.     void Start ()
    16.     {
    17.         currentPower = 0f;
    18.     }
    19.  
    20.     void Update()
    21.     {
    22.         // Vertical Input
    23.         if (Input.GetButtonDown("Vertical"))
    24.         {
    25.             // Vertical UP
    26.             int direction = 1;
    27.          
    28.             // Vertical DOWN
    29.             if (Input.GetAxisRaw("Vertical") < 0)
    30.                 direction = -1;
    31.             if (direction == -1){
    32.                 reverseState = true;
    33.             }
    34.          
    35.             // Add input value to newPower
    36.             int newPower = desiredPower + direction;
    37.          
    38.             // check if newPower is no bigger than 3 and no smaller than -1
    39.             if (newPower >= 0 && newPower <= 3)
    40.             {
    41.                 desiredPower = newPower;
    42.             }
    43.             if (newPower < 0 && newPower >= -1)
    44.             {
    45.                 desiredPower = newPower;
    46.             }
    47.         }
    48.  
    49.         //Turning boat ""BUG : Rot Speed is wrong after deccelerating and accelreating back""
    50.  
    51.         // use stationaryRotationSpeed if power is 0
    52.         if (currentPower == 0f) {
    53.             float rotation = Input.GetAxis ("Horizontal") * stationaryRotationSpeed;
    54.             rotation *= Time.deltaTime;
    55.             transform.Rotate (0, rotation, 0);
    56.         }
    57.         // when power is between 0 and 1, the rotation speed goes from lowest (stationary) to highest (power = 1)
    58.         else if (currentPower > 0f)
    59.         if (currentPower < 1f) {
    60.             float stationaryToRotSpeed = rotationSpeed * currentPower;
    61.             // limit the minimum rotation speed to stationaryRotationSpeed
    62.             if (stationaryToRotSpeed <= stationaryRotationSpeed) {
    63.                 stationaryToRotSpeed = stationaryRotationSpeed;
    64.             }
    65.             float rotation = Input.GetAxis ("Horizontal") * stationaryToRotSpeed;
    66.             rotation *= Time.deltaTime;
    67.             transform.Rotate (0, rotation, 0);
    68.         }
    69.         // rotation speed at its highest at power lvl-1
    70.         else if (currentPower == 1f) {
    71.             float rotation = Input.GetAxis ("Horizontal") * rotationSpeed;
    72.             rotation *= Time.deltaTime;
    73.             transform.Rotate (0, rotation, 0);
    74.         }
    75.         // rotation speed drops relative to how fast the boat is going (only beyond PwrLvl-1)
    76.         else if (currentPower > 1f) {
    77.             float rotation = Input.GetAxis ("Horizontal") * rotationSpeed / currentPower;
    78.             rotation *= Time.deltaTime;
    79.             transform.Rotate (0, rotation, 0);
    80.         }
    81.         // reverse rotation
    82.         if (reverseState == true)
    83.         {
    84.             float rotation = Input.GetAxis ("Horizontal") * stationaryRotationSpeed;
    85.             rotation *= Time.deltaTime;
    86.             transform.Rotate (0, rotation, 0);
    87.         }
    88.  
    89.         //we modify the increment by the time the last frame took to process
    90.         //this makes the change smoother using real-time
    91.         float adjustedIncrement = changeIncrement * Time.deltaTime;
    92.  
    93.         //if the power we want is more than the power we have
    94.         if (currentPower <= desiredPower - adjustedIncrement)
    95.         {
    96.             currentPower += adjustedIncrement;
    97.         }
    98.         //if the power we want is less than the power we have
    99.         else if (currentPower >= desiredPower + adjustedIncrement)
    100.         {
    101.             currentPower -= adjustedIncrement;
    102.         }
    103.         else
    104.         {
    105.             //match the desired speed exactly
    106.             currentPower = desiredPower;
    107.         }
    108.      
    109.         transform.position += transform.forward * currentPower * baseSpeed * Time.deltaTime;
    110.     }
    111. }
    112.  
     
    Last edited: Aug 2, 2015
  10. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    Glad you found it! Debugging is fun, eh?
     
  11. Hubardo

    Hubardo

    Joined:
    Apr 2, 2015
    Posts:
    22
    it could be if i knew how to do it correctly :)
    i actually couldnt find any problems with any of the values using Debug.Log, then, out of frustration i started manually debugging, systematically commenting out each section of the script until i found the culprit.
    and since you asked, for the future, is this a reasonable process to go through when such problems arise? i really just did what seems logical to me
     
  12. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    Yes, that's fine. For better/easier control you can look into breakpoints and tracepoints though, which will allow you to see all of the values of all variables when a certain point in the code is reached. Here's an excellent article on it, and proof that the Unity staff should go back to writing real tutorials instead of those silly semi-promotional videos they've been doing (you can't "search" through a video, after all). That's for Mono, but there's breakpoints (and more importantly tracepoints, which allow an action to be performed just before the break) in Visual Studio as well- or at least the pro version. You should definitely look into it, as it'll make more difficult-to-find bugs far far easier to locate.
     
  13. Hubardo

    Hubardo

    Joined:
    Apr 2, 2015
    Posts:
    22
    Very happy to know such a thing exists, that's awesome.
    cant wait for some high level bug hunting :D