Single Touch Problem

I am working on cocos2d-x v3.2

Some strange problem, I’ve noticed.
I have attached my eventListener to spriteA and not layer to which it is added…
I’ve implemented the onTouchBegan and on TouchEnded in a normal way…
Consider the code…

HelloWorld::onTouchBegan(...)
{
    if(spriteA->getBoundingBox().containsPoint(touch->getLocation()))
    {
        globalFlag = 1;
    }
    else
    {
        globalFlag = 2;
    }
}
HelloWorld::onTouchEnded(...)
{
    if(spriteA->getBoundingBox().containsPoint(touch->getLocation()) && globalFlag==1)
    {
        spriteA->removeFromParent();
    }
} 

Don’t worry about the declarations and other things. Assume that I can do them all without any problem.

So, here is my problem…
Case 1:
Use just 1 finger… Don’t touch the screen with 2nd finger (especially outside spriteA while this process otherwise BLAST :stuck_out_tongue: , I mean then you would have to see Case 2 )

Touch spriteA and release/raise your finger. spriteA should get removed.

WORKING PERFECTLY
Because when I touched the spriteA, my globalFlag is set to 1 and when I released my finger while keeping this finger inside spriteA, it removed this spriteA because my globalFlag was 1 and my touch ended’s locations was within spriteA.
Good Enough.

Case 2:
Now use 2 fingers for this procedure as stated below:
Touch spriteA with one finger and keep pressing… DON’T release/raise your this finger…
globalFlag should get set to 1…Right!!
Now, (don’t raise your first finger until said), touch outside spriteA with the 2nd finger and raise this 2nd finger.
Interesting thing is globalFlag will now change to 2… and now when I will raise/release my 1st finger which was still touching on spriteA… Now, spriteA won’t get removed because the globalFlag is changed to 2 although my touch location (in touch ended) is within spriteA’s boundingBox.

My Problem:
I don’t know why this happened… Or may be I was so unaware…
But I was expecting that when I am using singleTouch then until the things(all the 3 functions- onTouchBegan/Moved/Ended) of first touch are over then touch of 2nd finger should be ignored automatically by engine.

I figured out the workable workaround using some flags to make above thing work even if the player touches outside spriteA by mistake… But I could have achieved it exactly what I wanted if the 2nd touch would have been ignored automatically by the engine…

Any suggestions?

This is the order of the function calls according to what you described:

  1. onTouchBegan for touch #1 inside spriteA – this sets globalFlag = 1

  2. onTouchBegan for touch #2 outside spriteA – this changes globalFlag = 2

  3. onTouchEnded for touch #2 outside spriteA – nothing changes

  4. onTouchEnded for touch #1 inside spriteA – touch point is inside spriteA, but globalFlag is still == 2, so nothing happens

Does that make sense?

exactly this is what happened…
Yeah… but I don’t know why the (2) onTouchBegan came when (4) onTouchEnded for 1st touch was not over…

Touches don’t have to be serial. onTouchBegan will get called once a touch is detected and does not wait for a previous touch to end.

Maybe the confusion is that you’re using EventListenerTouchOneByOne instead of EventListenerTouchAllAtOnce and are expecting the touches to be processed serially?

EventListenerTouchOneByOne just means that it will call onTouchBegan, onTouchMoved, onTouchEnded, and onTouchCancelled for each touch detected, separately. So 4 touches will trigger 4 calls to onTouchBegan with only one touch passed in.

EventListenerTouchAllAtOnce will call onTouchesBegan (notice the plural), etc… passing in all touches to one function.

Your this line

explained the things clearly…

Also, you mean that if I use

then I hope with this my problem should get resolved… thanks :smile:

If you use EventListenerTouchAllAtOnce, you’ll have to change your callback functions to be the plural versions. Additionally, you’ll have to cycle through every touch passed in and keep track of which touch is which in each callback. Usually, it’s easier to use EventListenerTouchOneByOne.

Do you perhaps want to disable multitouch?

Do I really need to cycle through all touches… I mean my first touch should always be the one that I want :smiley:

Also, I am working on android

So, is it gonna solve my problem, I mean does it take care that 2nd touch is ignored while 1st touch activities aren’t over?
Also, if yes, then I think I can do so only on iOS and not for android because I don’t have option to disable multi touch on android platforms unlike the case of iOS where we have to enable it manually…

Hey,… I searched on google regarding the keyword for cocos2d-x

It seems that I am not the only one who wanted to make that work :smiley:

A person said that it works without any problem on iOS… May be the reason was that in iOS he hasn’t enabled multi touch explicitly.
For android, I got 2 possible solutions…

1st Solution:
One was setting a global flag to 0 inside the onTouchBegan until the touchEnded makes it 1… and onTouchBegan will return false until this global flag is 1…

2nd solution:
I need to modify Cocos2dxGLSurfaceView.java where i need to comment all the lines that I am mentioning below.
Thanks @rajan for this suggestion…

case MotionEvent.ACTION_POINTER_DOWN:
			final int indexPointerDown = pMotionEvent.getAction() >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
			final int idPointerDown = pMotionEvent.getPointerId(indexPointerDown);
			final float xPointerDown = pMotionEvent.getX(indexPointerDown);
			final float yPointerDown = pMotionEvent.getY(indexPointerDown);

			this.queueEvent(new Runnable() {
				@Override
				public void run() {
					Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown(idPointerDown, xPointerDown, yPointerDown);
				}
			});
			break;

However, I still need to try the 2nd solution, because if we’re commenting the above lines then how is it gonna detect even the first touch… :stuck_out_tongue:
@Rajan could you please explain why we need to comment that particular Case POINTER_DOWN

Thanks :smile:

With multi touch and EventListenerTouchAllAtOnce, you will still need to cycle through all the touches. For example, say the user touches the screen with two fingers simultaneously. One on your spriteA and one not. In the set of touches that is passed to onTouchesBegan, you don’t know if any of them are on spriteA unless you cycle through them. For the future callbacks, you’ll also need to be able to correlate the touch to the original one you saw that was not ignored… that way you don’t perform the logic in onTouchesMoved or onTouchesEnded using the wrong touch.

This is why it’s easier to use EventListenerTouchOneByOne. If you want to only consider one touch at a time once you have a valid touch, you could do something like this:

bool HelloWorld::init()
{
    ...

    touchInProgress = false;

    ...
}

bool HelloWorld::onTouchBegan(...)
{
    if(!touchInProgress && spriteA->getBoundingBox().containsPoint(touch->getLocation()))
    {
        touchInProgress = true;
        return true;
    }
    return false;
}

void HelloWorld::onTouchEnded(...)
{
    if(spriteA->getBoundingBox().containsPoint(touch->getLocation()))
    {
        spriteA->removeFromParent();
    }
    touchInProgress = false;
}

void HelloWorld::onTouchCancelled(...)
{
    touchInProgress = false;
}

This sets a boolean when a valid touch is detected. Then all touches are ignored until the valid touch has ended via either onTouchEnded or onTouchCancelled

@catch_up
See, The touch of android by default allows more than 2 touches. there is an array of touches in .java file which capture the 5 finger touch and perform the operations accordingly. I was too shocked with the results. I just hit and trialed. When I commented the above case of switch, the android only takes a single touch and will not register any touch till your old finger in touching the screen. I have implemented this feature in couple of my games where I just want to have a single touch and it works fine because it goes to other case below. Otherwise by default in any game of android if you keep on touching the screen and touch some other button with your second finger, it will detect the touch

Thanks @toojuice and @rajan :smile: