Strange behavior when adding Sprite with PhysicBody at runtime

Hi everybody,
i get a very strange behavior when i add a new sprite with physicbody to my layer while the game is running.

I’m using cocos2d-x 3.10

Here is what I do:

I have a trigger with physic body and a player with physic body on a layer inside a parallax node in a scene initialized with physics. On collision of the trigger and the player I create a new sprite with physic body and set the position of the new sprite to player position + Vec2(0, 300), what means above the players head, and add it to the same layer.

BUT: the new sprite does not appear at the expected position but at the bottom left corner of the screen. If I add a sprite without physic body at the same position it appears like expected above the players head.

I spend a lot of time trying to figure out whats going on, but I stuck.

Any help is appreciated!

Thanks a lot!

EDIT:
for collision detection I have a listener like this:

auto triggerListener = EventListenerPhysicsContact::create();
triggerListener->onContactBegin = CC_CALLBACK_1(IngameLayer::triggerCheck, this);

this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(triggerListener, this);

in triggerCheck i have this to spawn an enemy when player enters trigger and remove the trigger after execution:

if (bodyA->getNode() == m_player 
    && bodyB->getNode()->getTag() == ENEMY_TRIGGER_TAG) {
                    
         EnemyTrigger * trigger = (EnemyTrigger *) bodyB->getNode();
                    
         this->spawnEnemy(trigger->enemyType(), bodyB->getNode()->getPosition());
       
         bodyB->getNode()->removeFromParent();
                    
         return false;
}

spawnEnemy creates an enemy of the given type:

switch (enemyType) {
    case DEATHWHEEL:
    {
        Vec2 targetPos = pos + Vec2(0, 300); // above the trigger
        
        auto deathWheel = Sprite::create("deathWheel.png");
        
        float physicsRadius = deathWheel->getContentSize().width/2.0f * 0.7f;
        
        PhysicsMaterial material(10, 1.0f, 0.5f);
        
        auto physicsBody = PhysicsBody::createCircle(physicsRadius, material);
        physicsBody->setContactTestBitmask(0xFFFFFFFF);
        physicsBody->setCollisionBitmask(1);
        physicsBody->setAngularDamping(0.25f);

        deathWheel->addComponent(physicsBody);

        deathWheel->setPosition(targetPos);
        m_mainLayer->addChild(deathWheel);

        break;
    }
    default:
        break;
}

Can you show the code?

Edit: Also, anchor point and position are relative to the parent.

http://cocos2d-x.org/docs/programmers-guide/2/#sprites

http://cocos2d-x.org/docs/programmers-guide/2/#parent-child-relationship

I edit my first post with code samples. Hope you can see what I miss?

Ok, it becomes even stranger. In 1 of 20 runs the trigger behavior is as I expect it. all the other times not! I upload a video to show you this:

At the first intersection with the trigger, the “deathwheel” spawns above the trigger, like I want and code it ;). At the other intersections the “deathwheel” spawns at the bottom left corner. The spawn location is always the trigger position plus an vertical offset. I don’t understand this…

EDIT: strangeness level +5. If you take a closer look you can see that 1 frame before the first “deathwheel” spawns it is also located at the bottom left corner and then “jumps” at the given position.

Check mal ein, will ich mal anschauen :wink:

Yea I have exactly the same problem. I recently ported my game from 3.4 to 3.10 and I for one of my sprite as soon as I attach a physicsbody it will appear at the bottom left of the screen and if I remove the physicsbody it will appear at the position I set.

It’s working correctly on 3.4 but not on the most recent version.

If anyone has an idea on that problem.

I also seem to have the exact same issue, and its getting on my nerves.

anyone have a solution to this yet?

Besides returning to version 3.4, I didn’t find anything yet to solve this.

At first glance, it did indeed seem that my issues was similar to the ones mentioned above.

But after more investigation, it seems it in my case was more of a issue related to this

Cocos2d- didn’t like that i was spawning objects from inside the onContactBegin.
After queuing the actions and processing them in main loop, the weirdness disappeared.

I can understand that it would be bad practice to put ‘slow allocations’ in a place like onContactBegin, but it still seems weird to me that cocos just ‘lose’ the objects and they end up at 0,0 instead.
clearly this cant be intended behavior?

Can I ask, to be clear, this is happening in v3.10, but not in v3.4. Do you know if it happens in any other versions? I have a physics based game that started in 3.6 and I am at 3.10 now and I am not seeing the same thing.

Looking at how I do things, I am not using material or physicsBody->setAngularDamping(0.25f);

I ported my game from 3.6 to 3.10. In 3.6 everything works great. This happens only with 3.10.

I think @Limerock post could help, but i had no time to check this. I will try it and give you feedback.

I had this same issue with v3.12. There are issues both with adding and removing Sprites within onContactBegin. (I believe if you remove a Sprite within onContactBegin directly, it can crash the app.)

My way of dealing with it is to use CC_CALLBACK_0 within a runAction. Something like this:

    node->runAction(CallFunc::create( CC_CALLBACK_0(HelloWorld::addSpriteWithDelay, this, 0, newPos) ));

In the above case, the addSpriteWithDelay function is one that I wrote; all it does is to add the Sprite with a PhysicsBody.

0 and newPos are two arguments passed to my addSpriteWithDelay function. (In your own code, if you don’t need to pass any arguments to your own function, leave them out.)

If you use the callback, you can use addComponent or setPhysicsBody on the new Sprite within your callback function and the Sprite should work correctly. I just verified it on my own game. :slight_smile:

@slackmoehrle

We now expecting exactly same issue as author of this post. Could you please ask team to check this seriously and give solution to it - it sounds like critical bug. It seems happening if creating or removing Sprite in onContactBegin function

@energyy sure thing. Can you tell me if the code sample the OP posted is relevant to your situation or can you show me a sample of your code and onContactBegin

My code little different, but it easy to try out - I think it will be reproducible in 99%.

In our code we creating new Enemy when previous was killed, so code is different but logic/issue is same.

For simple test:

Create in loop new physics enabled sprite with specific position inside onContactBegin method. After running code some of sprites will start to appear on bottom of the screen instead of set position.

There is other guy seems having same issue:

Thanks. I will create a test case locally and see how things go for me. Please give me a day to get to this.

ok, if no luck to reproduce I will ask our dev to make simple code to test.