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:
- Once press left mouse button, the slider starts filling up until I click the button again.
- 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).