Search Unity

Help a beginner, how to store a value until key release?

Discussion in 'Scripting' started by WajdiWarasneh98, Aug 3, 2020.

  1. WajdiWarasneh98

    WajdiWarasneh98

    Joined:
    Jul 30, 2020
    Posts:
    4
    What i'm trying to do is to accumulate value while key is being held, and then stop accumulating once key is released, I've wrote this code but it does not work apparently --without errors though-, I cannot see where I made a mistake, im trying to do something like a cannon, where the force increases the longer u hold down a key.
    Here is the code: // If spacebar is held down, power increases each frame, if getkey is not spacebar, add force to object.
    Here is the code:
    public class PlayerMovement : MonoBehaviour
    {
    public Rigidbody Player;
    public float power = 20f;
    // Update is called once per frame
    void FixedUpdate()
    {

    if (Input.GetKey(KeyCode.Space))
    {
    power += 10 * Time.deltaTime;
    if (!(Input.GetKey(KeyCode.Space)))
    {
    Player.AddForce(0, 0, power * Time.deltaTime);
    }
    }
    }
    }

    I ALSO TRIED IT WITH WHILE LOOP:
    public class PlayerMovement : MonoBehaviour
    {
    public Rigidbody Player;
    public float power = 20f;
    // Update is called once per frame
    void FixedUpdate()
    {

    while (Input.GetKey(KeyCode.Space))
    {
    power += 20 * Time.deltaTime;
    if(!Input.GetKey(KeyCode.Space))
    {
    Player.AddForce(0, 0, power * Time.deltaTime);
    }
    }


    }
    }
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Based on your code I think you have a fundamental misunderstanding about how Update() and Input works in Unity.

    Every frame, Unity is going to run your Update() method one time. During that frame, all input data is the same for the entire frame and the entire Update method. In your code you are checking for
    Input.GetKey(KeyCode.Space)
    , and then INSIDE that if statement, you are checking for
    !(Input.GetKey(KeyCode.Space))
    . The negated version will never be true. Remember your entire update method is run once every frame and during the method, the values in Input will not change.

    What you should do is check for Input.GetKeyDown(...) and Input.GetKeyUp(...) in separate if statements to detect when the key is pressed and released.
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Please use code tags: https://forum.unity.com/threads/using-code-tags-properly.143875/

    Everything @PraetorBlue writes above is spot-on.

    GetKeyDown() will NOT work reliably in FixedUpdate() either.

    You need to gather input in Update() and act on it there, or if you must do physics, act on the input (store it in temporary variables) in FixedUpdate(), which is only for physics-facing stuff.

    Adding one more tidbit, here is some timing diagram help:

    https://docs.unity3d.com/Manual/ExecutionOrder.html
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Ah good catch @Kurt-Dekker I didn't notice op was using FixedUpdate for input capture as well!
     
  5. WajdiWarasneh98

    WajdiWarasneh98

    Joined:
    Jul 30, 2020
    Posts:
    4
    Hey man, a beautiful explanation, thanks :). so should I do two separate if statements for getkeyup/down?
     
  6. WajdiWarasneh98

    WajdiWarasneh98

    Joined:
    Jul 30, 2020
    Posts:
    4
    ty for notice :), well its input and physics at the same time, what should I do?
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Read input in Update(), store the input in temporary variables, act on the input in FixedUpdate(), as I noted above.
     
  8. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Yes, but like @Kurt-Dekker was saying, FixedUpdate doesn't run every frame so it's better to capture the input in Update, store it in a bool variable, then consume that in FixedUpdate by reading the bool and setting it back to false.
     
    WajdiWarasneh98 and Kurt-Dekker like this.
  9. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    In your case I would do all the "hold and charge" stuff in update, and only save the AddForce part for FixedUpdate, after the key is released.
     
    WajdiWarasneh98 likes this.
  10. WajdiWarasneh98

    WajdiWarasneh98

    Joined:
    Jul 30, 2020
    Posts:
    4
    Hey guys I appreciate the help from both of you, thanks!!, my code worked now I can launch a cannonball lol
    I know the code might be a bit messy but here it is:
    Code (csharp):
    1.  
    2. public class PlayerMovement : MonoBehaviour
    3. {
    4.     public Rigidbody Player;
    5.     public float power;
    6.     bool hold;
    7.     bool charge;
    8.     bool release;
    9.     // Update is called once per frame
    10.     void Update()
    11.     {  
    12.      
    13.      if (Input.GetKey(KeyCode.Space))
    14.         {
    15.             power += 1000 * Time.deltaTime;
    16.             Debug.Log(power);
    17.             hold = true;
    18.             }
    19.         if(Input.GetKeyUp(KeyCode.Space))
    20.         {
    21.         charge = true;
    22.   }
    23.         if(hold == true && charge == true)
    24.         {
    25.         release = true;  
    26.   }
    27.            
    28.            
    29.         }
    30.         void FixedUpdate()
    31.         {
    32.             if(release == true)
    33.             {
    34.                 Player.AddForce(0, 10, power * Time.deltaTime, ForceMode.VelocityChange);
    35.                 hold = false;
    36.                 charge = false;
    37.                 release = false;
    38.    }
    39.   }
    40.  
    41.    
    42. }
    43.  
     
    Kurt-Dekker likes this.
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Looks good to me! That's exactly how to do it.

    Also, the reason those close braces fail so often in code posted here is a combination of the VS/Mono editor handling copy/paste of code NOT as pure text (it uses some bastardization of rich text), the VS/Mono editor inconsistently handling tabs and spaces, and then the Javascript browser window on Unity forums failing to figure it out.

    To avoid this, when you paste code into the window, use Paste-and-match-style, if your browser has it. At least it will be closer. :)