oxygine / oxygine-framework

Oxygine is C++ engine and framework for 2D games on iOS, Android, Windows, Linux and Mac
http://oxygine.org/
Other
786 stars 173 forks source link

Bubbling in touch events #89

Open zmeyc opened 7 years ago

zmeyc commented 7 years ago

On iOS simulator TOUCH_UP and MOVE events are emitted once, but TOUCH_DOWN is emitted twice (with bubbling: true, then bubbling: false).

TOUCH_DOWN: bubbles=1
TOUCH_MOVE: bubbles=1
TOUCH_MOVE: bubbles=1
TOUCH_MOVE: bubbles=1
TOUCH_UP: bubbles=1
TOUCH_UP: bubbles=0

Steps to reproduce:

    _holder->addEventListener(TouchEvent::TOUCH_UP, CLOSURE(this, &GameScene::onTouchEvent));
    _holder->addEventListener(TouchEvent::MOVE, CLOSURE(this, &GameScene::onTouchEvent));
    _holder->addEventListener(TouchEvent::TOUCH_DOWN, CLOSURE(this, &GameScene::onTouchEvent));

void GameScene::onTouchEvent(Event *ev)
{
    if (ev->type == TouchEvent::TOUCH_DOWN)
        log::messageln("TOUCH_DOWN: bubbles=%d", (int)ev->bubbles);
    else if (ev->type == TouchEvent::MOVE)
        log::messageln("TOUCH_MOVE: bubbles=%d", (int)ev->bubbles);
    else if (ev->type == TouchEvent::TOUCH_UP)
        log::messageln("TOUCH_UP: bubbles=%d", (int)ev->bubbles);
}
jordan-woyak commented 7 years ago

This is an issue on more than just iOS. TOUCH_UP is emitted twice (not TOUCH_DOWN).

The second (bubbles:false) event is dispatched within "Actor::_onGlobalTouchUpEvent".

I can't make heads or tails of the intended logic within Actor involving _overred, _pressedButton, and _pressedOvered. It looks like it might be trying to add handlers to generate TOUCH_UP/MOVE events on an Actor that received TOUCH_DOWN previously, regardless of the current mouse position.

I can't help but think this needs a bit of an overhaul. It seems to be designed around originally only supporting a single pointer perhaps?

Each Actor maintaining its own mouse button state seems wrong in general. Why is this being done?

frankinshtein commented 7 years ago

It is known bug. there is workaround: you should check if 'bubbles' flag = false

example:

void GameScene::onEvent(Event *ev)
{
     if (ev->type == TouchEvent::TOUCH_UP && ev->bubbles == false)
     { 
         someStuff();
     }
}
frankinshtein commented 7 years ago

I can't help but think this needs a bit of an overhaul. It seems to be designed around originally only supporting a single pointer perhaps?

Each Actor maintaining its own mouse button state seems wrong in general. Why is this being done?

It is designed for multitouches. Thats why each actor has own state

jordan-woyak commented 7 years ago

It is designed for multitouches. Thats why each actor has own state

Yeah, but why is the state stored in each Actor? Why can't objects deriving from Actor register event handlers and deal with touch events normally on their own? It looks like the whole point of Actor keeping track of which pointer "overred" and "pressed" it is so it can register _onGlobalTouchMoveEvent and _onGlobalTouchUpEvent. Why are those handlers needed?

And then _overred is a pointer_index and _pressedButton is an array of pointer_index. So the Actor code can only remember a single "pointer" that "overred" or "pressed" it (per button). That doesn't seem multi-touch compliant.

TLDR: Why does Actor register touch event handlers at all? Why can't derived classes handle all the touch events as needed?