Home > Mobile >  Update() interrupting itself
Update() interrupting itself

Time:01-03

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;


public class StatReader : MonoBehaviour
{
    public float modifier;
    bool isIncrease = false;

    void Update()
    {
        CheckInput();
        Reading();
    }

    void CheckInput()
    {
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            Debug.Log("Input received.");
            if (isIncrease == false)
            {
                Slider slider = gameObject.GetComponent<Slider>();
                slider.value  = modifier * Time.deltaTime;
                isIncrease = true;
            }
            else
            {
                Slider slider = gameObject.GetComponent<Slider>();
                slider.value -= modifier * Time.deltaTime;
                isIncrease = false;
            }
        }

    }

    void Reading()
    {
        Slider slider = gameObject.GetComponent<Slider>();
        float readingOutputs = slider.value;

        if (readingOutputs <= 0f)
        {
            readingOutputs = 0f;

        }
        if (readingOutputs >= 100f)
        {
            readingOutputs = 100f;

        }
        Debug.Log(Mathf.RoundToInt(readingOutputs));
    }

}

As you can see from my script above, I'm trying to achieve the following goals:

  1. Once press left mouse button, the slider starts filling up until I click the button again.
  2. Once click it again, the slider starts depleting until I click the button again.

The problem is:

When I click the left mouse button, the slider will fill up but only for a moment notice. So the value increases to 0.000438 or something. Then it stops automatically. When I click again, it goes back to zero. I've been debugging it by myself for quite some time now. It seems like Update() is interrupting itself. Every frame it stops to check the input, which is why the increase/decrease was such a small value.

I have another problem actually:

Initially, I used FixedUpdate() instead of Update(). Weirdly, when I hit play , the program cannot pick up every input when I'm spamming the left mouse button. The problem went away once I changed FixedUpdate() to Update(). The problem is solved but I want to know why it happened.

Please help! Thanks a lot in advance!

CodePudding user response:

Update is called every frame. Your Update is not interrupted but rather only doing something when GetKeyDown returns true.

Well GetKeyDown is true only in one single frame when you started pressing the key.

And then you also immediately toggle between increasing and decreasing after adding the value once.

Anyway you should also avoid calling GetComponent in Update and rather store and re-use the reference

I would rather simply do something like

// already reference via the Inspector if possible
[SerializeField] private Slider _slider;

// a little helper method you can invoke via the context menu of your component
// allows you to a) already store the reference in the serialized field
// and b) you ca already see whether the reference is actually found as expected
[ContextMenu(nameof(FetchComponents))]
private void FetchComponents()
{
    // as a FALLBACK get the reference ONCE
    if(!_slider) _slider = GetComponent<Slider>();
}

private void Awake()
{
    FetchComponents();
}

void CheckInput()
{
    if (Input.GetKeyDown(KeyCode.Mouse0))
    {
        // simply invert the direction ONCE on key press
        isIncrease = !isIncrease;
    }

    // increase or decrease depending on the current flag state EVERY FRAME
    // Clamp your result value between 0 and 100
    var newValue = Mathf.Clamp(_slider.value   modifier * Time.deltaTime * (isIncrease ? 1 : -1), 0f, 100f);
        
    // apply the new value EVERY FRAME 
    // but only if it is actually different (-> hasn reached 0 or 100)
    // to avoid unnecessary calls of onValueChanged
    if(!Mathf.Approximately(_slider.value, newValue))
    {
        slider.value = newValue;
    }
}

Your other issue about FixedUpdate: This is the physics routine (and should only be used for physics related things usually). It is called on a fixed time base (by default usually every 0.02 seconds) => It is clear that some of your single-time input like GetKeyDown is missed by this method since there might be multiple Update frames in between two FixedUpdate calls => The GetKeyDown was true in a frame where there was no FixedUpdate call.

=> Thumbrule: Get (single-event) User input in Update. Then if you are dealing with physics apply this input in FixedUpdate (store it in fields meanwhile).

  • Related