Some Newly Created Nodes Appear at the Bottom-Left Corner of the Scene Despite the Set Position

So I got an instance of DrawNode, called Food, which is essentially just a solid yellow circle, created through this static method:

DrawNode* Food::create(const Vec2 &position)
{
    auto node = DrawNode::create();
    node->setPosition(position);
    node->drawDot(Vec2::ZERO, 5, Color4F::YELLOW);

    auto physicsBody = PhysicsBody::createCircle(5, PHYSICSBODY_MATERIAL_DEFAULT);
    physicsBody->setDynamic(false);
    physicsBody->setCategoryBitmask(2);
    physicsBody->setCollisionBitmask(1);
    physicsBody->setContactTestBitmask(1);
    node->addComponent(physicsBody);
    
    return node;
}

As you can see, it got a static physics body, used for collision detection. I set the position immediately after creation of the DrawNode. The dot and physics objects are placed relative to the position of the DrawNode (their parent), with zero offset.

Here’s the callback which is called right when contact between two objects is made:

bool MainScene::onContactBegin(PhysicsContact &contact)
{
    auto bodyA = contact.getShapeA()->getBody();
    auto bodyB = contact.getShapeB()->getBody();

    auto categoryBitmaskA = bodyA->getCategoryBitmask();
    auto categoryBitmaskB = bodyB->getCategoryBitmask();

    if (categoryBitmaskA != categoryBitmaskB)
    {
        if ((categoryBitmaskA == 1 && categoryBitmaskB == 2) || (categoryBitmaskA == 2 && categoryBitmaskB == 1))
        {
            auto foodNode = (categoryBitmaskA == 2 ? bodyA : bodyB)->getNode();
            if (foodNode != nullptr)
            {
                this->removeChild(foodNode);
                this->addFood(1);
            }

            return false;
        }

        return true;
    }

    return false;
}

As you can see, when a food instance collides with a body of a specific category mask, it gets destroyed and a new method MainScene::addFood is called to add a new instance.

So here’s how the method for adding new food looks like:

void MainScene::addFood(int count)
{
    auto visibleSize = Director::getInstance()->getVisibleSize();

    for (int i = 0; i < count; i++){
        auto location = Vec2(random((float)10, (float)(visibleSize.width - 10)), random((float)10, (float)(visibleSize.height - 10)));
        
        auto food = Food::create(location);
        this->addChild(food, 0, "food" + std::to_string(this->index));
        this->index++;
    }
}

As you can see, new food instances are created and placed randomly within the visible portion of the scene, using the Food::create method I’ve previously mentioned.

Now the thing is that when food instances are added to the scene in the MainScene::init method or using a scheduler, everything works as expected - new food instances are added in random positions within the visible portion of the scene.

However, when the Main::onContactBegin method triggers creation of food instances, things go wrong. That is, some food instances are placed in positions as specified using DrawNode::setPosition, but rest of them are placed at the bottom-left corner of the scene! You can see for yourself in the screenshot below:

Now if I modified portions of the Food::create method to create the dot and the physics body in the specified position, instead of being relative to the DrawNode, and setting the position of the DrawNode, things work perfectly:

DrawNode* Food::create(const Vec2 &position)
{
    auto node = DrawNode::create();
    // node->setPosition(position);
    node->drawDot(position, 5, Color4F::YELLOW); // Dot is centered on the specified position!

    auto physicsBody = PhysicsBody::createCircle(5, PHYSICSBODY_MATERIAL_DEFAULT, position); // Physics body has an offset equal to the specified position
    physicsBody->setDynamic(false);
    physicsBody->setCategoryBitmask(2);
    physicsBody->setCollisionBitmask(1);
    physicsBody->setContactTestBitmask(1);
    node->addComponent(physicsBody);
    
    return node;
}

Can anyone explain what is causing such behavior?

auto physicsBody = PhysicsBody::createCircle(5, PHYSICSBODY_MATERIAL_DEFAULT, position);

offset A Vec2 object, it is the offset from the body's center of gravity in body local coordinates.

I doubt this is the issue, but why are you still passing the position to the offset parameter? Do you actually need it to be offset, and if so, why by the passed in position, since that it makes no sense to do so?

Also, you should probably avoid using DrawNode, since each one you create and add to the scene is an extra draw call. Just use a sprite with a white texture that you can just call setColor on, if you need different colors, and if they all use the same texture, it’ll be a single draw call.

1 Like

I doubt this is the issue, but why are you still passing the position to the offset parameter?

I think you misunderstood. I said that the weird issue of the physics body and the circle appearing at the bottom-left of the scene doesn’t occur when I set the offset of the physics body, and the dot’s center, equal to the desired position, instead of setting the node’s position.

I just tried it out of curiosity and it seems to prevent the placement issue can recurring. Nevertheless, I need a proper solution.

Also, you should probably avoid using DrawNode, since each one you create and add to the scene is an extra draw call. Just use a sprite with a white texture that you can just call setColor on, if you need different colors, and if they all use the same texture, it’ll be a single draw call.

Thanks for pointing this out. I’ll switch to sprites in the future.

In the meanwhile, I want to know why this position issue occurs, and how to fix it.

Can you please look into it? Let me know if you need to see the rest of the codebase.

That is what your developer toolkit is for, like a debugger, conditional breakpoints, CCLOG statements and such, so dig into it and I’m sure you’ll find the source of the problem. The knowledge you gain from it will benefit you down the track when you come across similar issues.

1 Like

I never post to the forum without trying to debug it myself for an entire day or two. I’ve tried debugging it extensively at this point. If you face a weird issue, try to fix it yourself for days, finally post on the forum only to be asked to debug it yourself, then I don’t see a point of > 80% of all the threads in this entire forum.

My node’s position, when I retrieve using Node::getPosition, doesn’t match up with the actual position on the screen. Actual position is at the bottom-left corner of the scene, but the Node::getPosition method tells me that the position is elsewhere. And even more strange is the fact that it happens in ~50% of the cases; seems like something is happening at parallel.

If cocos2d-x and Chipmunk registers a specific position, but renders it on a different spot, this seems to be much more complicated than a common programmer’s fault.

Post sample code that reproduce your issue.

I really do understand your frustrations, and you are not the first person to come across a tough issue like this.

Just consider a few things first. This game engine has been around for quite a number of years, and many projects would be using that same physics code. Has it occurred to you that if there aren’t other posts about this issue, then it is most likely something in your own code that is causing it? I’m just being rational about this.

Approach the problem from a different angle. You’re too focused on the physics code, and you’re quick to be blame the game engine code. I assume you still haven’t tried out different types of nodes (in case DrawNode is the problem). Have you attempted to use a test sprite instead of DrawNode? That’s how I discovered the issue with your original post, because I used a Sprite, which instantly showed me that something was wrong with the positioning in your code.

It’s not that I or anyone else here isn’t willing to help, and I truly do want you to discover the source of this issue, but I think you’re giving up way too easily. How well do you know this game engine and its internal workings? For example, how Sprite and DrawNode is positioned, how Physics objects are positioned, how the physics engine passes the position to the node etc. If the answer is “not well”, then
that would be a good place to start.

Step back from the problem, make assumptions about what could be causing it, and follow those. If they lead nowhere, that’s fine, you’ve eliminated those reasons.

When you ask for help on here, what you’re effectively doing is asking others to use their time and effort to investigate this issue for you, literally what you would be doing anyway. The only way someone can give you an instant fix is if they’ve come across this before and solved it, which is how other posts with problems on this forum are lucky enough to get answered with a solution quickly.

For issues that have not been seen before, then it’s all just guesswork; no one has an instant solution. The only way to get it is to put time and effort into finding one, so don’t you think that is a little unreasonable to expect others to do this? I’m sure if someone has the time they will help in this way, but that is their choice, it shouldn’t be expected of them.

It’s very simple. Just create an instance of a Node, with physics body, inside a physical-contact-listener-callback for EventListenerPhysicsContact. The callback can be for EventListenerPhysicsContact::onContactBegin, or EventListenerPhysicsContact::onContactSeparate, or any other type of event; I don’t think it matters.

Example of creation of a node inside callback:

bool MainScene::onContactBegin(PhysicsContact &contact) {
    auto test = DrawNode::create();
    test->drawDot(Vec2::ZERO, 5, Color4F::MAGENTA);
    test->setPosition(300, 300);

    auto physicsBody = PhysicsBody::createCircle(5, PHYSICSBODY_MATERIAL_DEFAULT);
    physicsBody->setDynamic(false);
    test->addComponent(physicsBody);

    this->addChild(test, 10);
}

The node will appear sometimes in the set position (300, 300), and rest of the time in (0, 0), right after you trigger some collision/contact.

I debugged this and found that Node::setPosition gets called, soon after the node is created and added it to the scene, which sets the position to (0, 0). This is what calls it:

It’s the physics body implementation of cocos2d-x which is responsible for it. I don’t exactly know why this is triggered. I suspect that it has something to do with creation of the node inside the callback, which sometimes (maybe half of the time?) conflict with the calculations of the physics engine.

My question is, aren’t we supposed to create new nodes inside collision handlers?

@nahiyan You should search forum properly.
Anyways see this thread


Its a drawnode issue.
Better use sprite or dont call setposition.
Edit:
My advice to you after using Cocos for more than 5 yrs now, NEVER USE DRAWNODE period

Just consider a few things first. This game engine has been around for quite a number of years, and many projects would be using that same physics code. Has it occurred to you that if there aren’t other posts about this issue, then it is most likely something in your own code that is causing it? I’m just being rational about this.

You’re right, it’s very likely that it’s my piece of code which is causing it. However, I also considered the fact that cocos2d-x community is tiny. It’s nothing compared to Godot or even GameMaker Studio’s. The number is still large, but only a small fraction of them ever makes it up to the forums if they ever face a problem.

Approach the problem from a different angle. You’re too focused on the physics code, and you’re quick to be blame the game engine code. I assume you still haven’t tried out different types of nodes (in case DrawNode is the problem). Have you attempted to use a test sprite instead of DrawNode? That’s how I discovered the issue with your original post, because I used a Sprite, which instantly showed me that something was wrong with the positioning in your code.

I did try sprites after you mentioned it. Made no difference. And I even opted for a plain node with just a physics body. And I did approach from different angles, which you can find in my attached codes. You asked me why I set the offset of the physics body; well it was because I was trying to fiddle with it from various angles.

I truly do want you to discover the source of this issue

Believe me; that’s what I’ve been doing for the past couple of days. I’ve spent plenty of hours on this already. I’ve already looked into hundreds of lines of Chipmunk and cocos2d-x code. Tried to understand it better to see what caused the position to be set to (0, 0).

but I think you’re giving up way too easily

I didn’t give up, otherwise I’d not be spending time on this issue even after so many failed attempts. I can try to understand the inner workings of cocos2d-x and Chipmunk (which I’ve been using for physics) to some extent, but beyond that it’s better to ask someone who has better understanding than I do.

Step back from the problem, make assumptions about what could be causing it, and follow those.

Like I’ve said in the original post of this thread, I think it’s caused because I created a node, with physics body, inside a collision event callback. If I create the same node elsewhere, the problem wouldn’t occur. I want to know why.

When you ask for help on here, what you’re effectively doing is asking others to use their time and effort to investigate this issue for you, literally what you would be doing anyway.

I don’t think that’s always the case, since lot of people here are much more experienced with cocos2d-x than I’m. And moreover, I want someone else to be benefited from solutions to my problems. I’ve spent almost equal amount of time and effort solving other’s problems in this forum.

Even if people haven’t come across this exact problem, they can at least provide suggestions to help me figure out the cause of the problem.

The only way to get it is to put time and effort into finding one, so don’t you think that is a little unreasonable to expect others to do this?

If people found it unreasonable, then I don’t think they’d be volunteering to solve problems here in the first place. Most of the threads would be unsolved then. And I don’t expect anything. Whatever I get from this community is a bonus to me. And I always try to spend at least the same amount of time and effort to help others here.

I’m sure if someone has the time they will help in this way, but that is their choice, it shouldn’t be expected of them.

Since others get their problem solved, and there’s a lot of volunteers here, there is some chance of finding someone who spends their time and energy to attempt to solve my problem. And I hope discussing this problem will be of some use to others.

I switched to Sprite afterwards, the problem persisted. It doesn’t persist when I create the Node outside the collision callback function. I suspect that it has something to do with it. I just want to know what exactly is causing the problem.

I use draw node a lot. But I do it in a different way. Draw nodes are always a child to the same parent node. Also I create a bunch of draw nodes on game startup and store them in a vector. I then reuse them over and over without creating or destroying more.

ohh

I saw this before replying to you so…
And anyways you should use cocosthread, if you are creating new objects in onContactBegin

cocos2d::Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]() {
			// your code
		});
3 Likes

This is good advice. We should put this in our faq

Wow. This actually fixed the issue. I didn’t know about this thread issue. Thanks a lot!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.