Is onEnter() a predefined class method by Cocos2dX?

So I see people use onEnter() methods in their own classes.

Is onEnter() a predefined class by Cocos2dx or is it a tradition among OOP programmers when making their classes? Please give me a bit background about it. thanks (:

What are other functions like onEnter() ?

thanks :smile:

Basically it’s a (virtual) method called after the node is added into a running scene. This can occur multiple times if you remove a node or one of its parents and then add the node back into the scene. It’s the complement of onExit which is called when a node is removed from the running scene.

It’s just a hook to allow you to know when something has entered or exited the scene. Maybe you want signal to all units when a specific item or entity is added into the scene. Or maybe you want to lazy load and defer some initialization only after it’s actually put into the scene (say pre creating a pool of instances). Or maybe you just want to play a sound when an object enters the scene.

@stevetranby
hmmmm. . does it execute by itself or do you have to declare it like:

in HelloWorld.cpp/main game:

CCPlayer *player = CCPlayer::create(filename);
player->onEnter(); // <— do you have to do that?? or is it automatic?
addChild(player);

thanks for replying :smile:

Yes, its virtual method and called automatically.
It actually depends upon how are you implementing.

Suppose you’re creating a scene by using onEnter function
then onEnter() function will be called automatically and it doesnot need to return any object, I mean the object you created for the scene inside onEnter function.
But if you were creating the scene by ctor then you need to return the scene as an object.

No you don’t have to do that.

Also, one more thing,
as I said that you don’t need to return any object if you’re using onEnter() instead of ctor.
You must use ‘new’ keyword before creating the object of the class wherever you’re calling it, because you’re not returning any object,

While when you use ctor() instead of onEnter() , you need not use ‘new’ keyword as you’re returning the object and this object while been created has already used new keyword, And henec, wherever this is called, (unlike the one created using onEnter()) you don’t have to use ‘new’ keyword.

@iQD @stevetranby @catch_up @Maxxx

Well Im doing something wrong. I made my tile objects using this code:

Vector< Sprite* > vecTable;
Vector< Sprite* > qBox;
for (int i = 0; i < 3; i++) {

    for (int j = 0; j < 3; j++) {
        //row.push_back(i * j); // Add an element (column) to the row
        CCLOG("2d Vector  %d", i * j);
        _qBox = (CCqBox*)CCqBox::create("questionbutton.png");
        //_qBox->onEnter();
        
        _qBox->setPosition(Point( (visibleSize.width/2)-(( 3 * _qBox->boundingBox().size.width/2   )- (_qBox->boundingBox().size.width/2)   ) + (  i   * (_qBox->boundingBox().size.width * 1.1) - (_qBox->boundingBox().size.width * .1)  ) ,   (visibleSize.height * .6) + (_qBox->boundingBox().size.height + 10 ) *  j ));
        addChild(_qBox,101);
        qBox.pushBack(_qBox);
    }
    vecTable.pushBack(qBox); // Add the row to the main vector
}

the result:

so far so good. Now I want to attach touch Events in the “class itself” not in ‘HelloWorld.cpp’

Here’s What my class.cpp looks like:

CCqBox.cpp

void CCqBox::onEnter()
{
CCqBox::onEnter();
CCLOG(“CCqBox onEnter()”);

// Register Touch Event
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);

listener->onTouchBegan = CC_CALLBACK_2(CCqBox::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(CCqBox::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(CCqBox::onTouchEnded, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

}

void CCqBox::onExit()
{
// auto director = Director::getInstance();
// director->getTouchDispatcher()->removeDelegate(this);
Sprite::onExit();
}

bool CCqBox::containsTouchLocation(Touch* touch)
{
Size s = this->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);
return rect.containsPoint(convertTouchToNodeSpaceAR(touch));
}

bool CCqBox::onTouchBegan(Touch* touch, Event* event)
{
CCLOG(“Paddle::onTouchBegan id = %d, x = %f, y = %f”, touch->getID(), touch->getLocation().x, touch->getLocation().y);

//if (_state != kPaddleStateUngrabbed) return false;

// if ( !containsTouchLocation(touch) ) return false;

// _state = kPaddleStateGrabbed;
CCLOG(“return true”);
return true;
}

void CCqBox::onTouchMoved(Touch* touch, Event* event)
{
// If it weren’t for the TouchDispatcher, you would need to keep a reference
// to the touch from touchBegan and check that the current touch is the same
// as that one.
// Actually, it would be even more complicated since in the Cocos dispatcher
// you get Sets instead of 1 UITouch, so you’d need to loop through the set
// in each touchXXX method.

CCLOG("Paddle::onTouchMoved id = %d, x = %f, y = %f", touch->getID(), touch->getLocation().x, touch->getLocation().y);

// CCASSERT(_state == kPaddleStateGrabbed, “Paddle - Unexpected state!”);

auto touchPoint = touch->getLocation();

setPosition( Vec2(touchPoint.x, getPosition().y) );

}

void CCqBox::onTouchEnded(Touch* touch, Event* event)
{
//CCASSERT(_state == kPaddleStateGrabbed, “Paddle - Unexpected state!”);

// _state = kPaddleStateUngrabbed;
}

When I pressed those tiles (displayed above) , no TOUCH EVENT! How do I solve this :frowning: ? HelppP

Hi,
Few weeks back I implemented something similar. The implementation, however, was slightly different.
Anyways, is this class extending some Node class(layer, sprite, scene or anything else) .
If yes, then you can add even handler to that, as v3.x support attaching touch events to each node separately.

What exactly you want?
Do you want touch event for all the tiles one at a time or anyone can be touched any time.

Are you seeing any CCLog (“return true”)

What is this?
Shouldn’t you be using the rectangle of the tiles.
try to get to sprite of the tile and then
tile->getBoundingBox().contains(convertTouchToNodeSpaceAR(touch));

See, I think you missed this part… You must do what seems to be logical… I think this isn’t looking logical in your code.
Just change and check it if it works.

Also, I am not sure whether you should use convertTouchToNodeSpaceAR.
Instead of this I used convertTouchToNodeSpace.

If problem still persists, then you can tell again… But please check whether it is detecting the CCLogS that you’ve put in the console. If nothing is being shown on the console then your problem isn’t in the rest part of the code but in the implementation of onTouchBegan

this is my first time implementing this kind of Touch Handling where touch events are done in the ‘player class’ itself not in ‘HelloWorld.cpp/main game". To be honest this is what I want to do from now on. snippets of this code I got from cpp tests, Paddle-Ball example. One at a time is what I want to do. The yellow tile that contains my touch, that tile alone shall trigger whatever is inside "onTouchBegan’ . For example when I press the topleft tile, it alone becomes invisible. No feedback on CCLOG, so touchEvent is not working. I know Im wrong here. I just want to make it work :smiley:

my CCqBox.cpp Class is derived from Sprite Class. Ok, gimme a few sec to try your suggestions

man this is getting kinda frustrating lol. To think that Im having problem with "touch handling’ the very basic function of any game engine. We’re not even talking about 8-way joysticks here haha. How much more when I move to implementing Path-finding algorithms using grids here in Cocos2dx :frowning:

@catch_up
How do I get onEnter() to trigger inside my class?

void CCqBox::onEnter()
{
CCqBox::onEnter();
CCLOG(“CCqBox onEnter()”);

// Register Touch Event
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);

listener->onTouchBegan = CC_CALLBACK_2(CCqBox::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(CCqBox::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(CCqBox::onTouchEnded, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}

When I run the program, no feedback from CCLOG, so Im assuming onEnter() doesnt run like it’s supposed to

I think my error lies in here?

CCqBox* _qBox = (CCqBox*)CCqBox::create(“questionbutton.png”);

I think it’s a wrong way of creating/instantiating your class?

Then how else do you want to do that :smiley:
This is correct. And btw its also creating your tiles. Isn’t it? Then why are you thinking it is wrong way.

Do you ever trigger ctor() ?
It is done automatically.
You just overide it. if you won’t write it and override it with your statements then also it would be called.

Similary happens for onEnter().
You can override and once you create a new object of this class it would be called automatically.

Also, note that I’ve used this when I was creating a new scene.
So i am not sure what sense it makes when creating a sprite.
So, I am not sure whether onEnter is scene/layer specific or it can be applied o sprites (or in general to any node).
For this, you check the functions presents inside sprite node in the framework. If it is present then no problem.
I think it should be present because otherwise it should have given error.

However, I’ve used onEnter() way only once but I like this way. Unity also uses similar/same way.

I didn’t notice

Why are you calling
CCqBox::onEnter();
in above?
This should not be present anywhere, as I already told that it is called automatically.

Cocos2d-x revamped its touch events since v2.x so that we can use it on every node separately.
It made developers to write a bit more code. But I like it because it gives more flexibility in implementing something.
Anyways, it doesnot solves your problem… Nevermind.

Hey I saw my first response…
I forgot to give you my snippet

Inside onTouchBegan I used following snippet:

auto target = static_cast<Sprite*>(event->getCurrentTarget());
Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());

here I am using target-> before convertToNodeSpace(touch->getLocation());

which says that it will convert the touch location according to my target sprite.

You used,

where convertTouchToNodeSpaceAR(touch) is I think getting attached to “this” keyword by default.
Anyways, it should also have been correct because your target is “this” in your case.
Anyways, just try to do as I did…

As @catch_up already pointed out, that you are calling CCqBox::onEnter(); in CCqBox::onEnter();. This will create an endless loop. The error is definitely in there.

This has the same behavior as his code Rect rect = Rect(0, 0, s.width, s.height); return rect.containsPoint(convertTouchToNodeSpaceAR(touch));

Why even derive from Sprite? Does it have special behavior? If not, don’t derive, as it will just increase the vtable, slows it down and increases your inheritance tree.
Inheritance is not always a good thing.

@catch_up @iQD

thanks for replies guyz. I know this post will be of great help to others as well, as I believe many want to implement this kind of functionality.

But still, Im having problems, I dont think onEnter() on my CCqBox class runs automatically caused I dont see any feedback from CCLOG() which I placed inside… So I’ll post the whole code here, for you to see.

CCqBox.h // my Tiles class

#include “cocos2d.h”
USING_NS_CC;

class CCqBox : public Sprite
{
bool _state;

public:
CCqBox(void);
virtual ~CCqBox(void);

virtual void onEnter() override;
virtual void onExit() override;

bool containsTouchLocation(Touch* touch);
bool onTouchBegan(Touch* touch, Event* event);

// virtual CCqBox* clone() const;

};

CCqBox.cpp /// <— CCqBox.cpp

CqBox::CCqBox(void)
{
}

CCqBox::~CCqBox(void)
{
}

void CCqBox::onEnter() //this was supposedly to run automatically right?
{

CCLOG("CCqBox onEnter()");  //I dont see this on the log console, no feedback

auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);

listener->onTouchBegan = CC_CALLBACK_2(CCqBox::onTouchBegan, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

}

void CCqBox::onExit()
{
CCLOG(“did Exit hohohoho”); //no feedback as well on log console
}

bool CCqBox::containsTouchLocation(Touch* touch)
{
Size s = this->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);
return rect.containsPoint(convertTouchToNodeSpace(touch));
}

bool CCqBox::onTouchBegan(Touch* touch, Event* event)
{
CCLOG(“onTouchBegan id = %d, x = %f, y = %f”, touch->getID(), touch->getLocation().x, touch->getLocation().y); //no feedback again, so no touch

auto target = static_cast<Sprite*>(event->getCurrentTarget());  //from catch_up's code
Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());
target->setVisible(false);   // hide the Tile when clicked, but well, nothing happens lol

CCLOG("return true");
return true;

}

now try to Implement my class on GameScene.cpp

//create an object from CCqBox tile class

CCqBox sampleTile = (CCqBox)CCqBox::create( “questionbutton.png”);
sampleTile->setPosition(Vec2(visibleSize.width/2, visibleSize.height * .41));
addChild(sampleTile,200);

I am able to display a button. but when I click the button, no touch event. Do I have to make a listener or touch Dispatcher on GameScene.cpp as well? Im totally lost. I was trying to follow the Ball-Paddle example from Cocos2dx team.

I like this idea as well, separate touch functinality for separate objects. It’s what Im totally looking for aha :smile: It’s been a week and more since I’ve ported to V3 of Cocos2dx. I want to take advantage of it’s revamped power so I’ll be patient and learn it

I don’t notice any errors right away. Have you tried to set breakpoints in those methods to see if they get called?

@Jgod
Well I dont really know how to use breakpoints, aha. My only debug friend as of now is ‘CCLOG’ :smiley:

@Wuhao @walzer @corytrese hi experts. can you please help