Detecting first or second Mouse Button Release? - c#

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.

Related

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().

Unity Toggle Button Delay

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.

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.

Detect only a specific Keyboard combination in Unity

In my game I need to check for a specific keyboard combination, lets say Left Shift + B.
If I do it normally with
if(Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.B)) {
Debug.Log("correct");
}
It will accept everything as long as it has those two controls, so Left Shift + B, Left Shift + C + B, Left Shift + any keyboard button to be honest + B will return true as well.
My question is if I can detect somehow if ONLY those two were pressed, I already tried going foreach char c in KeyCode and detecting whether that Input was my B and then setting bool to correct or false but that doesn't really work.
Any ideas?
Event.current and OnGUI
Though usually it is not used so often anymore you can check the input in OnGUI using Event.current.
Every time a key goes down, store it in a list of currently pressed keys. When this keys goes up remove it from the list. Then you can simply check if the list contains the according keys and if the length matches the expected key amount.
public HashSet<KeyCode> currentlyPressedKeys = new HashSet<KeyCode>();
private void OnGUI()
{
if (!Event.current.isKey) return;
if (Event.current.keyCode != KeyCode.None)
{
if (Event.current.type == EventType.KeyDown)
{
currentlyPressedKeys.Add(Event.current.keyCode);
}
else if (Event.current.type == EventType.KeyUp)
{
currentlyPressedKeys.Remove(Event.current.keyCode);
}
}
// Shift is actually the only Key which is not treated as a
// EventType.KeyDown or EventType.KeyUp so it has to be checked separately
// You will not be able to check which of the shift keys is pressed!
if (!Event.current.shift)
{
return;
}
// As said shift is check on another way so we want only
// exactly 1 key which is KeyCode.B
if (currentlyPressedKeys.Count == 1 && currentlyPressedKeys.Contains(KeyCode.B))
Debug.Log("Only Shift + B");
}
It has to be done in OnGUI since there might be multiple events in one single frame. This is exclusive and will ony fire while Shift + B is pressed.
If you rather put this somewhere in your scene and make the values static
public class KeysManager : MonoBehaviour
{
public static bool ShiftPressed;
public static HashSet<KeyCode> currentlyPressedKeys = new HashSet<KeyCode>();
private void OnGUI()
{
if (!Event.current.isKey) return;
if (Event.current.keyCode != KeyCode.None)
{
if (Event.current.type == EventType.KeyDown)
{
currentlyPressedKeys.Add(Event.current.keyCode);
}
else if (Event.current.type == EventType.KeyUp)
{
currentlyPressedKeys.Remove(Event.current.keyCode);
}
}
ShiftPressed = Event.current.shift;
}
}
Then you can as before use something like
private void Update()
{
if (KeysManager.ShiftPressed && KeysManager.currentlyPressedKeys.Count == 1 && KeysManager.currentlyPressedKeys.Contains(KeyCode.B))
{
Debug.Log("Only Shift + B exclusively should trigger this");
}
}
Iterating with Input.GetKey through all KeyCode
Alternatively you could as commented check all possible keys.
However, this might or might not be an issue regarding performance. You'll have to test that and decide whether it is acceptable in your specific case.
using System.Linq;
...
// will store all buttons except B and LeftShift
KeyCode[] otherKeys;
private void Awake ()
{
// This simply returns an array with all values of KeyCode
var allKeys = (KeyCode[])Enum.GetValues(typeof(KeyCode));
// This uses Linq Where in order to only keep entries that are different from
// KeyCode.B and KeyCode.LeftShift
// ToArray finally converts the IEnumerable<KeyCode> into a KeyCode[]
otherKeys = allKeys.Where(k => k != KeyCode.B && k != KeyCode.LeftShift).ToArray();
}
private void Update()
{
if(Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.B) && !AnyOtherKeyPressed())
{
// Happens while ONLY LeftShift + B is pressed
}
}
// Return true if any other key
// is pressed except B and LeftShift
private bool AnyOtherKeyPressed()
{
foreach (var keyCode in otherKeys)
{
if(Input.GetKey(keyCode)) return true;
}
return false;
}
Maybe we worry too much and it doesn't matter (I woudln't believe that but just theoretically ^^) than you could even take it one level up and make it more flexible.
[Serializable]
public class KeyCombo
{
// Note I'll be lazy here .. you could create a custom editor
// for making sure each keyCode is unique .. but another time
public List<KeyCode> keyCodes = new List<KeyCode>();
// This will show an event in the Inspector so you can add callbacks to your keyCombos
// this is the same thing used in e.g. Button onClick
public UnityEvent whilePressed;
// Here all other keyCodes will be stored
[HideInInspector] public KeyCode[] otherKeys;
// Return true if any other key
// is pressed except B and LeftShift
public bool AnyOtherKeyPressed()
{
foreach (var keyCode in otherKeys)
{
if (Input.GetKey(keyCode)) return true;
}
return false;
}
}
public List<KeyCombo> keyCombos = new List<KeyCombo>();
private void Awake()
{
// This simply returns an array with all values of KeyCode
var allKeys = (KeyCode[])Enum.GetValues(typeof(KeyCode));
foreach (var keyCombo in keyCombos)
{
// This uses Linq Where in order to only keep entries that are different from
// the ones listed in keyCodes
// ToArray finally converts the IEnumerable<KeyCode> into a KeyCode[]
keyCombo.otherKeys = allKeys.Where(k => !keyCombo.keyCodes.Contains(k)).ToArray();
}
}
private void Update()
{
foreach (var keyCombo in keyCombos)
{
if (keyCombo.keyCodes.All(Input.GetKey) && !keyCombo.AnyOtherKeyPressed())
{
keyCombo.whilePressed.Invoke();
}
}
}
With this you can now add multiple KeyCombos and check them individually - However be aware that every additional keyCombo also means one additional iteration through all other keys so ... it's far away from perfect.
You can use Event.current.modifiers if you're doing combined keystrokes like Alt + Q etc. Something like this
if (!Event.current.isKey || Event.current.keyCode == KeyCode.None) return;
switch (Event.current.type) {
case EventType.KeyDown:
if (Event.current.modifiers == EventModifiers.Alt) {
switch (Event.current.keyCode) {
case KeyCode.Q:
break;
default:
break;
}
}
break;
default:
break;
}

c# panel image only updates half the time

For my programming class we are required to make a memory match game. When the player clicks on a panel an image is displayed. The player clicks on two panels, if the images match they are removed, if they are different they are turned face down.
The problem I am having with this is that only the image from the first panel gets displayed, even though I am using the same line of code to display the images from both panels, and use Thread.Sleep to pause the program after the second tile has been picked. I don't understand why this is happening, any help would be appreciated.
private void tile_Click(object sender, EventArgs e)
{
string tileName = (sender as Panel).Name;
tileNum = Convert.ToInt16(tileName.Substring(5)) - 1;
//figure out if tile is locked
if (panelArray[tileNum].isLocked == false)
{
pickNum++;
//although the following line of code is used to display the picture that is stored in the tile array
//what is happening is that it will only display the picture of the first tile that has been picked.
//when a second tile is picked my program seems to ignore this line completely, any ideas?
panelArray[tileNum].thisPanel.BackgroundImage = tiles[tileNum].tileImage;
if (pickNum == 1)
{
pick1 = tileNum;
panelArray[tileNum].isLocked = true;
}
else
{
pick2 = tileNum;
UpdateGameState();
}
}
}
private void UpdateGameState()
{
Thread.Sleep(1500);
if (tiles[pick1].tag == tiles[pick2].tag)//compares tags to see if they match.
{
RemoveTiles();
}
else
{
ResetTiles();
}
pickNum = 0;
guess += 1;
guessDisplay.Text = Convert.ToString(guess);
if (correct == 8)
{
CalculateScore();
}
}
try this:
(sender as Panel).BackgroundImage = tiles[tileNum].tileImage;
you have to be sure that your tile_Click method is associated to both panel...

Categories

Resources