setTouchEnabled deprecation

So, the setTouchEnabled method is deprecated, and now we have this redundant code everywhere:

_touchListener = EventListenerTouchOneByOne::create();
_touchListener->onTouchBegan = CC_CALLBACK_2(ScrollView::onTouchBegan, this);
_touchListener->onTouchMoved = CC_CALLBACK_2(ScrollView::onTouchMoved, this);
_touchListener->onTouchEnded = CC_CALLBACK_2(ScrollView::onTouchEnded, this);
_touchListener->onTouchCancelled = CC_CALLBACK_2(ScrollView::onTouchCancelled, this);
    
_eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this);

I mean… Why?? It is seriously cumbersome, and it would be great if cocos2d-x didn’t try to lamba enable EVERYTHING. If you want to, that’s OK, I guess, just at least provide a shortcut.

I have a CCLayer subclass, I want to control the touchEnabled property in a single line of readable code. This is not readable:

KDGameScene::sharedScene()->getBoardLayer()->getEventDispatcher()->setEnabled(true);

Thanks,

I have same question…
why disign so ???

Layer should not be an event controller class anymore, and any classes should have the ability of receiving events.
EventDispatcher has unified all event dispatching.
Before, we have CCTouchDispatcher, CCKeyboardDispatcher…, etc.
Now, we just need one EventDispatcher.
If you like the old controller codes. You could very easily to achieve that.
For example, adding a new method called YourClass::setTouchEnabled

void YourClass::setTouchEnabled(bool enabled)
{
_touchListener = EventListenerTouchOneByOne::create();
_touchListener->onTouchBegan = CC_CALLBACK_2(YourClass::onTouchBegan, this);
_touchListener->onTouchMoved = CC_CALLBACK_2(YourClass::onTouchMoved, this);
_touchListener->onTouchEnded = CC_CALLBACK_2(YourClass::onTouchEnded, this);
_touchListener->onTouchCancelled = CC_CALLBACK_2(YourClass::onTouchCancelled, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this);
}

Another thing is if a listener is added by addEventListenerWithSceneGraphPriority, the event will be dispatched by the draw order of scene graph.
That means the node at the top of screen will receive event first.

In the 2.x version, you have to set the priorities by yourself. It’s very very hard to manage the order of dispatching.

So I don’t know why you hate the new EventDispatcher, anyway EventDispatcher is designed by me and all guys who have joined the design.
The principle is

  • Any Nodes should not contain event controller codes.
  • Any classes should have the ability to access events.
  • All events should be dispatched by the same strategy, that’s why we need the new EventDispatcher

If you guys don’t like it, please be more specified about the reason.
If you guys have better approaches, feel free to let me know. I’m glad to correct all my mistakes if there’re.

Thanks a lot @dumganhar. I apologize for not mentioning that the new underlying design is 10x more awesome, there is no doubt about that. It made my logic a lot simpler, and fixed bugs I didn’t know I had.

However, since cocos2d originated from cocoa, we have setUserInteractionEnabled in cocoa, but not in cocos2d. From a high level, this is really frustrating to beginners. Also, it is easy to write the method you mentioned, but it has to be copied over every subclass that derives from Layer, which can be a lot.

I feel a shortcut for this is simply a must.

Thanks,

@dumganhar I’m all fine with the new dispatching mechanism, but I’m having some serious issues when having too many overwriting of Menu objects (all children of a ScrollView), in some cases the EventListenerTouchOneByOne attached to each node in the view is catching right (so I can transfer the touch info to the scrollView below), in some other cases it does not. And after click is validated (touchEnded), then it works again.

So in general, I am still fighting with the right solution to allow buttons on top of scrollView to let the scrollView drag while click is initiated on the button, and this was working fine with Cocos2dx even so it’s kind of tricky.

Before I try to extract the code that is the source of the problem, I’d like to know if a similar issue was experienced by someone else, and in general if there’s a way to chat with someone about it, that would be a blast. I’ve been loosing many days on this issue already with the previous version, I’d love to have support so I don’t end up playing tricks for days again.

Thanks!

I got it, when using addEventListenerWithSceneGraphPriority, one need to make sure to call removeEventListenersForTarget before to avoid multiple listeners on the same object, in which case the first one called is not well defined AND may change over time after events are getting triggered.

@Mazyod,

I feel a shortcut for this is simply a must.

Yep, probably, I think providing some macros for simplifying the listener registration will better.
Something like

class MyObject
{
public:
    CC_ENABLE_TOUCH_ONE_BY_ONE(MyObject)
};

#define CC_ENABLE_TOUCH_ONE_BY_ONE(klass)
protected: \
EventListener* _touchListener; \
public: \
void setTouchEnabled(bool enabled) \
{ \
    _touchListener = EventListenerTouchOneByOne::create(); \
    _touchListener->onTouchBegan = CC_CALLBACK_2(klass::onTouchBegan, this); \
    _touchListener->onTouchMoved = CC_CALLBACK_2(klass::onTouchMoved, this); \
    _touchListener->onTouchEnded = CC_CALLBACK_2(klass::onTouchEnded, this); \
    _touchListener->onTouchCancelled = CC_CALLBACK_2(klass::onTouchCancelled, this); \
    _eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this); \
} \

I’m finding it difficult to make a single node remove a listener for a specific EventCustomListener.

Currently, we only have the option to remove a specific listener object, but that requires the function having a reference to that listener. It would be great if we can remove the listener by just giving the string it listens to and its target object.

Something like this:

_eventDispatcher -> removeCustomEventListener( "some_event", this );

@erwanmaigret wrote:

I got it, when using addEventListenerWithSceneGraphPriority, one need to make sure to call removeEventListenersForTarget before to avoid multiple listeners on the same object, in which case the first one called is not well defined AND may change over time after events are getting triggered.

Hi, @erwanmaigret,
Listeners with scene graph priority doesn’t need to invoke removeEventListenersForTarget manually, since it’s called at the destructor of Node.
You said you had problems with ScrollView and the subclass of Menu. Could you provide a demo for reproducing the issue you faced?
Feel free to upload a zip ball or send me an email. :slight_smile:

@lance_gray wrote:

I’m finding it difficult to make a single node remove a listener for a specific EventCustomListener.

Currently, we only have the option to remove a specific listener object, but that requires the function having a reference to that listener. It would be great if we can remove the listener by just giving the string it listens to and its target object.

Something like this:

_eventDispatcher -> removeCustomEventListener( "some_event", this );

removeCustomEventListener( "some_event", this );, is the second parameter a Node?
I assume it’s true, but if a custom event listener uses fixed priority, how to remove the listener by this API?

@dumganhar wrote:

@lance_gray wrote:

I’m finding it difficult to make a single node remove a listener for a specific EventCustomListener.

Currently, we only have the option to remove a specific listener object, but that requires the function having a reference to that listener. It would be great if we can remove the listener by just giving the string it listens to and its target object.

Something like this:

_eventDispatcher -> removeCustomEventListener( "some_event", this );

removeCustomEventListener( "some_event", this );, is the second parameter a Node?
I assume it’s true, but if a custom event listener uses fixed priority, how to remove the listener by this API?

I think it should only be used by those in the scene graph priority. If it was used with fixed priority listeners, it could either assert or simply do nothing, probably a simple log. I’m not sure.

@dumganhar wrote:

@Mazyod,

I feel a shortcut for this is simply a must.

Yep, probably, I think providing some macros for simplifying the listener registration will better.
Something like

class MyObject
{
public:
    CC_ENABLE_TOUCH_ONE_BY_ONE(MyObject)
};

#define CC_ENABLE_TOUCH_ONE_BY_ONE(klass)
protected: \n> EventListener* _touchListener; \n> public: \n> void setTouchEnabled(bool enabled) \n> { \n>     _touchListener = EventListenerTouchOneByOne::create(); \n>     _touchListener->onTouchBegan = CC_CALLBACK_2(klass::onTouchBegan, this); \n>     _touchListener->onTouchMoved = CC_CALLBACK_2(klass::onTouchMoved, this); \n>     _touchListener->onTouchEnded = CC_CALLBACK_2(klass::onTouchEnded, this); \n>     _touchListener->onTouchCancelled = CC_CALLBACK_2(klass::onTouchCancelled, this); \n>     _eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this); \n> } \n> ```

Thanks for this, it helps a lot! I am already using CC_SYNTHESIZE all over the place, so it’s not too bad to adopt macros for this.

Good question

Cocos2dx = cocos2d Sux

The designer of the platform doesn’t have the concept of “backward compatibility” in mind

It is so regretful to start with this platform. At the end of the day our effort will all be gone and everything has to start over again.

Hi, I’m really new to c++ and cocos2d coming from an objective-c background. Could you advise the best place to put the #define for CC_ENABLE_TOUCH_BY_ONE? Would that be in a separate header file or in my Game Layer class header? Thanks.