Issue with changes of TouchLocationState on Android

I’ve added buttons for a menu where I’d like the user to be required to touch and release on the button area in order to launch the event.

I’m having a bad time trying to understand when the State property of a TouchLocation is supposed to change. I thought it would be Pressed on the first frame and Moved for the rest of the time until the frame after releasing where it would change to Released. Am I mistaken about it?

This is my Button class:

    public partial class Button {
            private bool _pressingDown;

        public void Update(GameTime gameTime) {
            TouchCollection touchState = TouchPanel.GetState();
            if (touchState.Count > 0) {
                TouchLocation touch = touchState[0];

                if (this.Rectangle.Contains(touch.Position)) {
                    if (touch.State == TouchLocationState.Pressed)
                        _pressingDown = true;
                    if (_pressingDown && (touch.State == TouchLocationState.Pressed || touch.State == TouchLocationState.Moved))
                        _isHovering = true;
                    if (touch.State == TouchLocationState.Released) {
                        _isHovering = false;
                        if (_pressingDown)
                            Click?.Invoke(this, new EventArgs());
                    }
                } else {
                    _pressingDown = false;
                    _isHovering = false;
                }
            }
        }
    }

I just have two buttons whose Update methods are called one after another. What freaks me out is that the first button works as intended while the second one no. Debugging it shows me that for the second button the TouchLocationState is always set as Moved.

Here is a sample of what happens:
TouchIssue

Any idea of what could I be doing wrong? Thanks in advance!

There are a couple of obvious problems.

_pressingDown is never initialised until a touch event occurs. This doesn’t look to me like it is your problem but it is bad and will probably bite you at a later date. Just add =false;

If you don’t get touch events , _pressingDown and _isHovering are not updated. If you lose an event the state of these becomes undefined , just clear them when there are no touch events

You are only handling the first touch event. Logically you may think this is fine, but I have had cases when the order of touch events changes. put finger one on screen and move it around . keep it on and do a second touch, then remove the first finger and funny things can happen

I can’t tell from the little code you have shown why the second button isn’t working, post some more and we will look at it

Any subsequent call to GetState() will return a previous Pressed event as Moved.
It’s best to get the input state once, preferably in Game.Update() , and pass the state down to any classes in our library. do this for for all input states, keyboard, touch, mouse. this way your controls will avoid problem like for example if the mouse has moved inbetween calls to getState, keys are released / pressed, etc.

1 Like

Thanks for your input!

Isn’t false the default value of a bool? Does it make any difference then to initialize it to false? Or is it because it’s good practice for better understanding and easier to translate to a different language? Sorry for the bunch of questions, I’m just trying to learn the proper way of doing things.

You’re right about the variables not being updated if losing an event, I didn’t contemplate that. I’ve already added another else statement to set them to false so that they are always reset when not doing stuff.

Regarding the handling of just the first touch event… Yeah, I know that working with gestures is a pain but in this case even trying to do all weird things I could think of it works fine as no matter what you do with other fingers, only the first one is relevant. You’re right though that this isn’t the way to go if I want to do more complex things so any input to make it more robust would be appreciated.

There isn’t really too much code… This is the part of the class compiled when targeting the Android project. In my Shared project there is the _isHovering variable, Draw method, the event… not relevant to this. And the Update call for each button is done successively in the game Update.

This worked, thanks! I shouldn’t have assumed that retrieving a state during the same frame would get me the same state at all. I haven’t thought that calling GameState() would be what updates the state

Never assume a default value for a variable.

The language may, or may not set the memory that the variable represents to something, more often than not it doesn’t.

Also be aware that debug and release may behave differently, debug initialises a default value, release does not

So you get a bug from a user (release mode) and you cannot recreate it because you are in debug

Ok, thanks for the help :slightly_smiling_face:

I think it’s compiler dependent. The Visual Studio compiler for sure defaults it to false. I’ve checked this many times in the past, but also just confirmed it here to be sure. Not sure what compiler the OP is using but it sounds like they found the problem and it wasn’t related.

Either way, I completely agree with you, best practice to always initialize your variables! So with that in mind, here’s something interesting…

class Program
{
  static void Main(string[] args)
  {
    TestClass t = new TestClass();
    Console.WriteLine(t.MyBool); // Compiler warning

    bool myBool;
    Console.WriteLine(myBool); // Compiler error
  }
}

public class MyClass
{
  private bool _myBool;

  public bool MyBool => _myBool;
}

Whatchu doin’, Microsoft!?