Unity Toggle Button Delay - c#

I'm trying to make it so my toggle = !toggle doesn't just repeat OVER and OVER when you press it once because it kind of toggles on and off over and over if you hold it it just keeps toggling like 30 times a second and I want it to have a delay here is the gist of my code
private class AirJump_Patch
{
private static void Postfix (Locomotion.Player __instance)
{
List<InputDevice> list = new List<InputDevice>();
InputDevices.GetDevicesWithCharacteristics(InputDeviceCharacteristics.HeldInHand |
InputDeviceCharacteristics.Controller | InputDeviceCharacteristics.Right, list);
list[0].TryGetFeatureValue(CommonUsages.secondaryButton, out
Plugin.AirJump_Patch.secondaryButton);
if (Plugin.AirJump_Patch.secondaryButton)
{
Plugin.AirJump_Patch.jumpToggled = !Plugin.AirJump_Patch.jumpToggled;
}
if (!Plugin.AirJump_Patch.jumpToggled)
{
//DO CODE
}
ECT ECT.
I tried adding delay using StartCoroutine, doesn't work
I tried adding delay using simple C# wait things, doesn't work
This is in a private static void. I cannot change that. Is there a reasonably easy way to make the toggle not repeat 30 times a second with a 0.5 second delay or so?

Maybe you could use a simple timer field like
private float lastToggle;
and then
if(Time.time > lastToggle + 0.5f)
{
lastToggle = Time.time;
Plugin.AirJump_Patch.jumpToggled = !Plugin.AirJump_Patch.jumpToggled;
}
Alternatively you could actually handle it really only once e.g. like
private bool alreadyToggled;
if(Plugin.AirJump_Patch.secondaryButton)
{
if(!alreadyToggled)
{
Plugin.AirJump_Patch.jumpToggled = !Plugin.AirJump_Patch.jumpToggled;
alreadyToggled = true;
}
}
else
{
alreadyToggled = false;
}
now it is really only handled once per button press.

Related

Why method with an await Task.Delay inside an if statement is not working in C#?

I'm sorry if the tittle is a bit confusing.
I have an array-sorting webapp in Blazor.
This is the important piece of code:
<MudButton OnClick="Sort" Disabled="Sorting" Variant="Variant.Outlined" >Sort</MudButton>
<MudButton OnClick="Accelerate" Disabled="#(!Sorting)" Variant="Variant.Outlined">Finish</MudButton>
#code{
public bool Sorting { get; set; } = false;
public bool Accelerating { get; set; } = default!;
public void Sort()
{
Sorting = true;
Bubble();
}
public void Accelerate()
{
Accelerating = true;
}
public async void Bubble()
{
while (!IsSorted(List))
{
//algorithm
StateHasChanged();
if (!Accelerating)
{
await Task.Delay((Speed - MAX_SPEED) * -1 == 0 ? 1 : (Speed - MAX_SPEED) * -1);
}
}
Sorting = false;
Accelerating = false;
StateHasChanged();
}
}
The sorting part works just fine.
When I click the Accelerate button the await Task.Delay should be skipped.
But when I do, the whole application freezes like this:
It won't respond. Nothing in console.
Where is the problem? Thanks
I'm guessing that when Accelerating becomes true, your CPU usage skyrockets.
Awaiting the delay gives the UI a chance to respond to user input, but without it, it can't. Once Accelerating becomes true, you end up in an infinite loop that occupies the UI thread entirely, and all user input gets put in a queue waiting for the UI thread to be freed, which never happens.
The line
Accelerating = false;
Will flip Accelerating to false the 2nd time you click the button, thus opening things up for Task.Delay to run.
The problem was the 'StateHasChanged()'
It should have been inside the if.

How do I get a button that is held down to change what it is doing after a power up ends?

In the game I am trying to make. When I am holding my fire button and I pick up a power up SuperShot, it continues to fire my regular laser unless I release my fire button and press it again. The same thing happens again when the power up ends. I have researched and I cant seem to figure out a way to check on where the power up is active while holding the key down.
private void Fire()
{
if (Input.GetButtonDown("Fire1"))
{
if (SuperShotIsActive)
{
superShotFiringCoroutine = StartCoroutine(SuperShotFireContinuously());
}
else if (!SuperShotIsActive)
{
firingCoroutine = StartCoroutine(FireContinuously());
}
}
if (Input.GetButtonUp("Fire1"))
{
StopCoroutine(firingCoroutine);
StopCoroutine(superShotFiringCoroutine);
}
}
You might be able to fix this by looking away from the button itself and into the code of the actual firing of the weapon.
//psuedocode-ish example. Just for the concept
//not necessarily the best idea to use a for loop but maybe it works for you.
FireContinuously()
{
for(int foo = 0; foo < ammo; foo++)
{
if(!SuperShotIsActive)
{
//normal firing code you have goes here
}
else
{
//supershot code goes here
}
}
}
In FireContinuously() (which I assume is a loop of some sort) you can add a check before each shot to see if the player now has the powerup and the necessary logic to change to the appropriate SuperShotFireContinuously(). Do the opposite for SuperShotFireContinuously() to change to FireContinuously().

Animation should play only on pressing the button

I have an issue when playing animation in Unity. I made a transaction and set a bool on the animation. The issue here is that if I have an animation on a loop it won't stop. If I unloop it, it would play only once. What I actually want from this is to play only when the player presses the button. Right now my code looks like this. I tried to set the bool to false in different places, but it didn't have the right effect. I would appreciate any idea. Thanks
private void Inflations()
{
inflationTimer -= Time.deltaTime;
//if hands are in mount area inflate
if (OVRInput.GetDown(OVRInput.Button.Any))
{
if (inflationTimer <= 0 && rightHand.inflated)
{
if (inflated)
{
inflationTimer = inflationSpawn;
inflated = false;
inflationAnimator.SetBool("Pressed", true);
//we can add inflations only if they are under 2 and if the button is pressed and released
inflations++;
}
else
{
inflationAnimator.SetBool("Pressed", false);
}
tempo.SetInflations(inflations);
}
}
if (OVRInput.GetUp(OVRInput.Button.Any))
{
if (!inflated)
{
inflated = true;
}
}
if (inflations >= 2)
{
inflationAnimator.SetBool("Pressed", false);
state = stueState.TakeInflator;
inflationsDone = true;
}
}
#ecco is right, you need two states for it
Without seeing your Animator Controller, you could use something like this;
//...
Stack<Action> _animations = new Stack<Action>();
private void Inflations()
{
// ...
if (OVRInput.GetDown(OVRInput.Button.Any))
{
if(inflated){
// your code
_animations.Push(() => inflationAnimator.SetBool("Pressed", true));
// ...
}
}
}
private void Update(){
if(_animations.Count > 0){
var currentAnimation = _animations.Pop();
currentAnimation();
}
}
This eliminates the need for a lot of if checks and is nice to use.
Note: I used lambda expression there for simplicity. You can read more about it in here. And you can read more about Stack containers here
The update function is gonna check if there are any animations in Stack, if there are, it will automatically execute it once and remove it from the stack.

Detecting first or second Mouse Button Release?

I want to know how to detect if the user has released the mouse button the first time, or the times after that:
Pseudo-Code:
if *first* (Input.GetMouseButtonUp(0))
{
do something
}
if *second, third, fourth..etc.* (Input.GetMouseButtonUp(0))
{
do something else
}
I really have no idea on how to accomplish this. I'm sure it's pretty simple though!
This is only an idea, but you could do this using a flag variable, like this:
private static bool WasFirstTimeReleased = false;
if (Input.GetMouseButtonUp(0))
{
if (!WasFirstTimeReleased)
{
WasFirstTimeRelease = true;
//do your stuff for first time
}
else
{
//do your stuff for all other times
}
}
Generally, you have to remember somewhere how many times button was released. Just create field in yours class:
private int clicks = 0;
then:
if (Input.GetMouseButtonUp(0))
{
if(clicks == 0)
{
// do something on first click
}
else
{
// do something on further click
}
clicks++;
}
If the object where you store clicks counter is created each time you press mouse button then mark counter using static word.
Keep track of mouse clicks:
int _leftUp;
void Update()
{
var leftUp = Input.GetMouseButtonUp(0);
if (leftUp) _leftUp++;
// etc ...
}
Easiest way to accomplish this would be to use a counter to check the number of times the user has released the button.
private int releaseCounter = 0;
And then in an if statement:
if (Input.GetMouseButtonUp(0)) {
releaseCounter++;
//If you know on which release you want the code to be executed,
//replace the x with that number.
if (releaseCounter == x) {
//your code here
}
//If you want the code to be executed at set intervals.
//replace the x with the interval number.
if(releaseCounter%x == 0) {
//your code here
}
}
Hope I helped.

Making an Alarm Clock with multiple alarm times

I am trying to make a programmable alarm clock. It should output a melody (.wav) at different moments of time. I used a usercontrol to make a digital clock. I have a timer for showing a progressbar to every second and a button that starts the process. I know exactly the times I want so I don't need any other button. I made some functions where I complete the times I need.
public void suna3()
{
userControl11.Ora = 01;
userControl11.Min = 37;
userControl11.Sec = 50;
}
and on the button click I called them. But when I start the program it is taking only the last time I made (the last function). How can I make it take all the functions?
private void button3_Click(object sender, EventArgs e)
{
userControl11.Activ = true;
suna1();
userControl11.Activ = true;
suna2();
}
I think the problem is that you are using the same timer for three different events, changing the settings of it three times. This results in only the final settings being used - the older settings are not remembered - they are overwritten.
The solution is to create a new timer for each event, each timer having its own separate settings.
You need a usercontrol for each alarm time, or change your user control so that it takes in an array of times to trigger the alarm at.
For multiple usercontrol instances, your code could look something like this:
public void suna1()
{
userControl11.Ora = 02;
userControl11.Min = 27;
userControl11.Sec = 20;
}
//...
public void suna3()
{
userControl13.Ora = 01;
userControl13.Min = 37;
userControl13.Sec = 50;
}
The alternative is to change your usercontrol so that it accepts a list of times, or has an AddAlarm() method. Something like this:
public void suna1()
{
userControl11.Alarms.Add(new Alarm() { Ora = 02, Min = 27, Sec = 20 };
//or "userControl1.AddAlarm(2, 27, 20);" if you go the method route
}
//...
public void suna3()
{
userControl11.Alarms.Add(new Alarm() { Ora = 01, Min = 37, Sec = 50 };
}

Categories

Resources