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?