[Solved] Dynamically create sprite on custom event

Hi guys,

I’m developing a small multiplayer card game with cocos2d-x. Server is up and running, and I can kinda play with a text-based client. Now it’s time for a graphical client. I have subclassed Layer in order to create my play scene, and in my init() I start a new thread for communicating with the server. On server message, a custom “server_msg” event is dispatched. All this stuff works, but I need to create a new sprite to represent a server message (namely a card played). My scene class have a public playCard() method, but it doesn’t seem to work inside the event dispatcher (it does outside).

This is the code:

Match* Match::playCard() {
    myCard = Sprite::create("card.png"); // myCard is a public Sprite* member of Match
    myCard->setPosition(Vec2(240, 66));
    myZone->addChild(myCard); // myZone is a public Zone* member of Match. Zone is a subclass of LayerColor
    return this;
}

bool Match::init() {
    if (!Layer::init()) return false;
    // ...
    myZone = Zone::create();
    this->addChild(myZone);
    // If I issue a this->playCard() here, it works
    // ...
    auto serverListener = EventListenerCustom::create("server_msg", [&](EventCustom* event) {
        // ...
        if (cmdCode == CARD_PLAYED) {
            this->playCard(); // This doesn't work
            // But if playCard() is called outside the listener, I can manipulate (i.e scale) the sprite here
        }
    }
    this->_eventDispatcher->addEventListenerWithFixedPriority(serverListener, 1);
    // ...
}

Any help?

I’ve been debugging and it seems to be a texture error. After calling placeCard(), myZone has the new child, but myCard->_contentSize is zero. If I place the following code before calling Sprite::create(“card.png”);

GLenum err = glGetError();
if (err != GL_NO_ERROR) {
    cocos2d::log("OpenGL error 0x%04X in %s %s %d\n", err, __FILE__, __FUNCTION__, __LINE__);
}

It logs a GL_INVALID_OPERATION, so Texture2D::initWithMipmaps always fails. Any idea?

Maybe you are running it on a different thread.
You should run it on the GL thread:

Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
... your code
1 Like

I love you <3

This code works:

Match* Match::playCard() {
    Director::getInstance()->getScheduler()->performFunctionInCocosThread([&]() {
        myCard = Sprite::create("card.png");
        myCard->setPosition(Vec2(240, 66));
        myZone->addChild(myCard);
    });
    return this;
}

Thank you very much, mate :smile: