How do the experts here deal with this problem

Here is my problem , I have 2 button sprites on my screen a Left sprite and a Right Sprite.
Now I have something like this in my code

For detecting when a button is pressed I have this

void Player_Controls::ProcessTouches(const std::vector<cocos2d::Touch*>& touch , cocos2d::Event* event)
{
    for(int i=0 ; i<touch.size() ; i++)
    {
                 
        Touch* t = touch[i];
        Point pA = t->getLocationInView();
        pA = Director::getInstance()->convertToGL(pA);
                
        if(LeftArrow->boundingBox().containsPoint(pA))
            //Left button pressed
    
        else if(RightArrow->boundingBox().containsPoint(pA))
           //Right button pressed
    }
    
}

For detecting when a button is unpressed

void Player_Controls::ProcessTouchesEnded(const std::vector<cocos2d::Touch*>& touch , cocos2d::Event* event)
{
    if(touch.size()==1)
    {
        Touch* t = touch[0];
        Point pA = t->getLocationInView();
        pA = Director::getInstance()->convertToGL(pA);

         if(LeftArrow->boundingBox().containsPoint(pA))
            //Do something the player just lifted his finger of the Left Arrow

        else if(RightArrow->boundingBox().containsPoint(pA))
             //Do something the player just lifted his finger of the Right Arrow       
    }
}

Now this all works fine. However there is only one scenario in which it fails. If the player is pressing the left button and his finger gradually slides to the right and then he lifts his finger of in that case my program has no way of knowing that the left sprite was untouched so my program keeps on processing left touch. How can I solve this problem ? There is some space between the two buttons. I wanted to know if there was a way for to say that

  if the finger slides to a space not occupied by the Left or right sprite then do something

How do I program detecting slides ? What would be the best way to solve this issue ?

You can handle that with onTouchesMoved callback just as you did with onTouchesBegan and onTouchesEnded.

Add a Player_Controls::ProcessTouchesMoved

void Player_Controls::ProcessTouchesMoved(const std::vector<cocos2d::Touch*>& touch , cocos2d::Event* event)
{
    ProcessTouchesEnded(touch, event);
    // Or do something else
}

Edit:
Or you may use touch->getStartLocation to know at which position the user pressed first and slided

For example you can simply modify your ProcessTouchesEnded and use :

Point pA = t->getStartLocationInView();

The result will be : Wherever the user slide and end the touch event, we will only consider the origin of the touch. :wink:

I have a slightly different solution. But it depends on what you mean by “button”.

Buttons typically do their action when they are released (not when they are pressed). Touch a button and slide off of it and if you release off of the button then that button wont do anything. That is how the MenuItem class works.

But I think you might be talking about something else. Something that I call a “touch pad”.

For my touch pad controls, I want the touch area that is touched to be active, regardless of where the finger started the touch.
And for a touch area that is not touched, I don’t want it to be active.

Taking this approach eliminates the issue of starting on a touch pad and ending off of it and the touch control wrongfully staying active. It also solves another problem that you did not mention. When the touch moves/slides from touch pad A to touch pad B. Shouldn’t that active control then transition from A to B. I think that is what users would expect.

e.g.
For things like gas pedal and brake pedal, this makes since. Sometimes the user will lift their finger to go from gas to brake. This will trigger a touch end and touch start. Easy to detect.

Sometimes they will slide their finger from gas to brake. This will just trigger a touch moved a bunch of times depending on how fast they move their finger and how far it moves.

But, in either case, the user expects a transition to occur since they were touching the gas and are now touching the brake. Make sense? It would be really frustrating as a user if you slide from gas to brake and the gas keeps on going :wink:

To implement touch pads that solve the above issues, I do the following in a HUD class.

Create a C array of a custom structure to track the touches (shown below).
Since the ptr to the touch is consistent over the phases of the touch (began, moved, ended, canceled), I can capture a pointer to the Touch. But I never directly access the touch through that pointer. That could be problematic and Apple states you should not do that. Probably the same on all platforms. But on iOS, Android and WP8.x it is ok to compare the pointer of touches in touch events that I receive to see if they match one of the active touches in the array of custom structs that I define below called _hudMultipleTouches.

Then in the HUD init method, I cycle through the five _hudMultipleTouches and set touch = nullptr.

typedef struct {
    cocos2d::Vec2			pStart;
    cocos2d::Vec2			pLastMove;
    cocos2d::Vec2			pEnd;
    cocos2d::Touch *	                touch;
    tTouchPhase                         phase;
} tTouchObject;

const static int NUMBER_OF_TOUCH_TRACKING_BINS = 5;

Class HeyaldaHUD : public cocos2d::Layer
{
private:
        tTouchObject            _hudMultipleTouches[NUMBER_OF_TOUCH_TRACKING_BINS];
}

For processing touches I do the following.

onTouchesBegan: Then for each touch that begins, cycle through _hudMultipleTouches and pick one of the empty bins, e.g. that has touch == nullptr and assign the touch location to pStart and pLastMove and assign its pointer to touch in the struct object that .

onTouchesMoved: When the touch moves, for each touch, cycle through the touches in _hudMultipleTouches if one has a pointer that is equal to touch in the stuct, update the pLastMove.

onTouchesEnded and onTouchesCanceled: When the touch ends / is canceled, for each touch, cycle through the touches in _hudMultipleTouches and if one has a pointer that is equal to touch in the struct, update the pEnd, do any end processing you want, and set touch = nullptr in the _hudMultipleTouches bin that ended. That frees that bin in the custom struct for reuse.

Then, for each of the events above, call a method called userTouchesChanged.
In that method, set local flags at the start of the method for your touch pads that assume none are touched.

Then cycle through the five touches in _hudMultipleTouches and for any that have touch != nullptr, use the pLastMove as the point to compare to see if it is in one of your touch pad rects.
If it is in one of your touch rects, then set the local flag for it, e.g. gasPedalTouched = true.
Then move on to the next touch bin until all five are processed.

Then at the end of that userTouchesChanged method, call your HUD delegates to tell them e.g. gasPedalTouched = false and brakePedalTouched = true.

I have been using this technique on iOS for about 5 years and on Android and WP8 for a little over two years now in multiple games and it works good.