Why is an action in my "if" block executing in the "else" conditions?

I’m having a weird issue, that I’m sure is user error… I have a tree of if statements to determine how a prompt GUI should be worded, and it also determines what happens if you push a button. Most of my conditions seem to work totally fine, but for some reason one of them is acting strangely. I have, nested in an “else” block, an “if” and “else” block. But for some reason, when I create the scenario that would present me with the “else” statement’s conditions, and I press the D Key, it executes my code in both the “if” and “else” blocks. Here’s the code:

		else{
			if(!emptyPlanet){
				Debug.Log("Introduce to new friend GUI activated");
				GUI.Label(Rect(0,LTT, Screen.width, LTH),"Press D to introduce your cargo to a new friend.

Press Spacebar to take him/her elsewhere.");
if(Input.GetKeyDown(KeyCode.D)){
emptyPlanet = false; //is this redundant once isActive = false?
carryOver.SadCatman.SlotB = Cargo;
carryOver.SadCatman.isActive = false;
carryOver.currentCargo = “empty”;
//load “new home” avatars for both aliens
Debug.Log(“You shouldn’t be reading this if the planet was empty before the delivery!”);
}
}
else{
Debug.Log(“Make this alien’s new home GUI activated”);
GUI.Label(Rect(0,LTT, Screen.width, LTH),"Press D to make this planet your cargo’s new home.

Press Spacebar to take him/her elsewhere.");
if(Input.GetKeyDown(KeyCode.D)){
carryOver.SadCatman.SlotA = Cargo;
carryOver.SadCatman.isActive = false;
//load “new home” avatar for alien in Slot A
carryOver.currentCargo = “empty”;
emptyPlanet = false; //is this redundant once isActive = false?
}
}
}

Let me know if you need to see the whole “if” tree block. I’ve already tried swapping the contents of the if and else blocks and made the “if” read if(emptyPlanet) instead of looking for the inverse to be true, but it still produces the dual results.

What am I not catching?

The reason is pretty simple :wink: You have this code in OnGUI. OnGUI is called for multiple reasons:

  • layouting
  • repainting
  • input events

The layout and the repaint event are fired once every frame. Input events such as MouseDown, KeyDown, KeyUp, … are of course only fired once. Your problem is that you use the Input class within OnGUI. The Input class is frame based, so during one frame the input has a certain state.

So if you press the “D” key, Input.GetKeyDown(KeyCode.D) will return true until the next frame. Since OnGUI is called at least two times per frame you process your code two times. Since you change your if condition when you process your code for the first time, the second time it will execute the else block, all within the same frame.

So you simply shouldn’t use the Input class in OnGUI or if you do, make sure you only process it in one of the events. However in OnGUI you usually use the Event class to process Mouse or keyboard events:

// I guess you use UnityScript?
var e = Event.current;
if(e.type == EventType.KeyDown && e.keyCode == KeyCode.D){

Note: the Event system handles key input differently. It wraps the systems keyboard input. That means if you hold down a key, the key is repeated at the systems repeatrate.

If you want to use Input.GetKeyDown, do something like this:

var e = Event.current;
if(e.type == EventType.Repaint && Input.GetKeyDown(KeyCode.D)){

This ensures that you only process the input during the repaint event.

Definitely handy to see the whole tree, probably post it to pastebin.

Are you absolutely sure that it’s running these blocks? IE: A breakpoint in each of them gets hit in the same turn? Because what I suspect is that this is actually happening is it’s doing both, but not in the way you think it is.

Notice how the else block has the final line emptyplanet = false?

If this is in update, what is happening is that the first time this if block fires, and emptyplanet is true, the ELSE block runs. The last line sets emptyplanet to false, and then 16ms later (at 60fps) the D key is likely still held down, so it runs through the same if block, but now does the other half of the if statement.

Few possible solutions:

  1. Add a flag for the keypress so it can only fire once.
  2. Force a delay between possible key events.