Buttons suddenly stop working

Ok… This is an odd one, and I haven’t yet got a working test case (and may not be able to). So, here is best description I can give so far…

Every now and then, Buttons (and other clickable elements) will suddenly stop reacting to events. This happens with both hover and clicks. This can happen anywhere in my UI, including in my login screen, start screens and in the game itself.

Sometimes, it is ALL buttons, sometimes it may just one, or all buttons in a Panel or Window.

Sometimes, you can make them start working again by hovering over another button that is working (often with a tooltip), and then going back to the broken button.

Sometimes, they don’t stop working completely, but may not activate over their full area. For example, hovering over the borders of the button will trigger hover events, but hovering over the text of the button wont.

It’s proved impossible to narrow down a single chain of events of that seem to trigger this, but parts of my game are worse than others. I can however reproduce fairly consistently in one particular place :-

  • I have a LoginAppState. This adds a login screen using various elements.
  • Upon login, this appstate is deactivated (the various UI elements are hidden using effects)
  • The CharacterSelectAppState is then activated, showing its elements using effects.
  • This means as one appstate deactivates, and the next activates, both are running effects.
  • The CharacterSelectAppState has a “Logout” button. Clicking this deactivates the CharacterSelectAppState, which hides its elements using effects, and reactivates LoginAppState.

If I rapidly cycle between the two, doing login, logout, login, logout, login, logout (usually 3 times). This usually results in the buttons in the character selection stop working.

I put some extra debug output inside Screen.getEventElement() to try and work out what was happening. It appeared that the collision there is not colliding with the element at all. results is either empty, or sometimes finds the parent element instead.

Now I am guessing this is some z-order thing? I tried outputting the values of Element.getZorder() and Element.getWorldTranslation().z. The former was alway zero. The later seemed to decreases with each cycle. Whether this means anything or not I have no idea.

Sorry I can’t give you any more to go on just yet. I should say that this has been a problem for me to varying degrees for some time. I’ve been putting off trying to fix it because I’m sure its going to be a pig to solve :S

RR

When you are able to repo this…is the entire button a problem, or can you still use it if you mouse over the very edge of the button?

It depends. Sometimes it’s the whole button, sometimes it’s at the edges. There seems to be no pattern to it other than something bad will eventually happen.

Something else to add I’ve just noticed though. If I am VERY careful not to trigger any button hover effects (or clicks) while the hiding/showing is going on, It seems a little less likely to freeze. Although I did see it happen in the end.

@rockfire said: It depends. Sometimes it's the whole button, sometimes it's at the edges. There seems to be no pattern to it other than something bad will eventually happen.

Something else to add I’ve just noticed though. If I am VERY careful not to trigger any button hover effects (or clicks) while the hiding/showing is going on, It seems a little less likely to freeze. Although I did see it happen in the end.

Likely you are correct about the z-order issue. I’m thinking that z-order is not resorting to stay within the bounds of the ui screen-level element count and eventually pushing child elements (or itself) outside of the 0-1 range. I’ll see if I can figure out where this is happening and fix it.

EDIT: Could be as simple as me forgetting to resort and offset the next available z-order index when removing screen level elements. Should know sometime today.

@rockfire
Oh… one more question that will help me narrow this down.

When using an AppState, there are two options for handling elements:

  1. Create and add them to the screen when the class is instantiated, then call hide (or use the new method that auto-hides) which essentially removes them from the scene but still keeps the element indexed as a child element of it’s parent. Then in initialize you would call show or showWithEffect and in cleanup you would call hide or hideWithEffect.
  2. The other option is to create the elements when the class is instantiated, but instead of adding/hiding them at that time, in initialization you call addChild (or addElement) and in cleanup either removeChild (or removeElement) or hideWithEffect and have the effect destroy on hide (which basically removes the element and indexing).

Which of the above are you currently doing?

More or less option 2, except all the creation is done in initalize() as well, not in contructor.

On initialize(). The elements are actually not added directly to the screen, but added to a parent element (that is setAsContainerOnly()) which takes up the whole screen area. They are then hidden, then the showWithEffect() is called. I haven’t ported these to the new addChild() yet.

On cleanup(). All the elements have hideWithEffect() called with destroyOnHide set to true. At this point I also hide the parent element as well, also with an effect.

[java]effectHelper.destroy(layer, Effect.EffectType.FadeOut); // This is the parent

/* These are all contained in layer */
effectHelper.destroy(panel, Effect.EffectType.SlideOut, Effect.EffectDirection.Top);
effectHelper.destroy(play, Effect.EffectType.SlideOut, Effect.EffectDirection.Right);
effectHelper.destroy(logout, Effect.EffectType.SlideOut, Effect.EffectDirection.Bottom);
[/java]

As I type this, I wonder if that may not be a good thing to do.

EDIT

Yup… it seems that may be causing the problem in this case. I changed this to …

[java]
effectHelper.destroy(versionText, Effect.EffectType.FadeOut);
effectHelper.destroy(banner, Effect.EffectType.FadeOut);
effectHelper.destroy(infoPanel, Effect.EffectType.FadeOut);
effectHelper.destroy(loginWindow, Effect.EffectType.FadeOut);

    app.getAlarm().timed(new Callable<Void>() {
        public Void call() throws Exception {
            app.getLayers().removeChild(layer);
            return null;
        }
    }, UIConstants.UI_EFFECT_TIME + 0.1f);

[/java]

… and the problem hasn’t show itself again. The “getAlarm()” bit is my own code to just run a task after a certain amount of time. I looked at ExecuteAction, wondering if that would do the same think, but it needs a Transformable, and im not sure what that is :slight_smile:

I am still seeing the issue elsewhere once in game, somwhere I don’t think i’m using that same flawed technique. will investigate some more.

@rockfire said: More or less option 2, except all the creation is done in initalize() as well, not in contructor.

On initialize(). The elements are actually not added directly to the screen, but added to a parent element (that is setAsContainerOnly()) which takes up the whole screen area. They are then hidden, then the showWithEffect() is called. I haven’t ported these to the new addChild() yet.

On cleanup(). All the elements have hideWithEffect() called with destroyOnHide set to true. At this point I also hide the parent element as well, also with an effect.

[java]effectHelper.destroy(layer, Effect.EffectType.FadeOut); // This is the parent

/* These are all contained in layer */
effectHelper.destroy(panel, Effect.EffectType.SlideOut, Effect.EffectDirection.Top);
effectHelper.destroy(play, Effect.EffectType.SlideOut, Effect.EffectDirection.Right);
effectHelper.destroy(logout, Effect.EffectType.SlideOut, Effect.EffectDirection.Bottom);
[/java]

As I type this, I wonder if that may not be a good thing to do.

EDIT

Yup… it seems that may be causing the problem in this case. I changed this to …

[java]
effectHelper.destroy(versionText, Effect.EffectType.FadeOut);
effectHelper.destroy(banner, Effect.EffectType.FadeOut);
effectHelper.destroy(infoPanel, Effect.EffectType.FadeOut);
effectHelper.destroy(loginWindow, Effect.EffectType.FadeOut);

    app.getAlarm().timed(new Callable<Void>() {
        public Void call() throws Exception {
            app.getLayers().removeChild(layer);
            return null;
        }
    }, UIConstants.UI_EFFECT_TIME + 0.1f);

[/java]

… and the problem hasn’t show itself again. The “getAlarm()” bit is my own code to just run a task after a certain amount of time. I looked at ExecuteAction, wondering if that would do the same think, but it needs a Transformable, and im not sure what that is :slight_smile:

I am still seeing the issue elsewhere once in game, somwhere I don’t think i’m using that same flawed technique. will investigate some more.

Yeah… all TemporalActions require a Transformable (2D Framework crap). I’ll likely add a way of doing this through the EffectManager that doesn’t need to be tied to anything as it’s quite useful!

Ok… this info gives me a bit more to work off of. My assumption about this is once the z order is pushed outside of the acceptable range, ray casting excludes this from the results as the ray never actually collides with the element. Hopefully I’ll be able to narrow down where I made the mistake quickly and get this resolved. Every time I have tried to work on this I can never repo the error which makes it difficult to find a solution for.

I think I know how to simulate my assumption and if it works, then I’ll be able to get this resolved.

@t0neg0d said: Yeah... all TemporalActions require a Transformable (2D Framework crap). I'll likely add a way of doing this through the EffectManager that doesn't need to be tied to anything as it's quite useful!

Ok… this info gives me a bit more to work off of. My assumption about this is once the z order is pushed outside of the acceptable range, ray casting excludes this from the results as the ray never actually collides with the element. Hopefully I’ll be able to narrow down where I made the mistake quickly and get this resolved. Every time I have tried to work on this I can never repo the error which makes it difficult to find a solution for.

I think I know how to simulate my assumption and if it works, then I’ll be able to get this resolved.

Oh ok cool :slight_smile: So you have encountered this before? Having such a thing in the EffectManager would also be awesome. Good luck tracking this down.

@rockfire said: Oh ok cool :) So you have encountered this before? Having such a thing in the EffectManager would also be awesome. Good luck tracking this down.

Yeah… I’ve seen it once or twice, but could never figure out a way to repo it so I could fix it =( Hopefully I’ll get it this time.