Error at this line: arrowBody->setDynamic(false);

Hello Devs! I run this code: arrowBody->setDynamic(false); when sprite body’s collided each other.

But I have this error:

Aborting due to Chipmunk error: This operation cannot be done safely during a call to cpSpaceStep() or during a query. Put these calls into a post-step callback.
Failed condition: !space->locked
Source:/Users/riq/progs/cocos2d-x-3rd-party-libs-src/contrib/ios-x86_64/chipmunk/src/cpBody.c:174

Full Code:

if (1 == a->getCollisionBitmask() && 2 == b->getCollisionBitmask() || 2 == a->getCollisionBitmask() && 1 == b->getCollisionBitmask()) {
        arrowBody->setDynamic(false);
        arrow->stopAction(action);
    }
1 Like

That’s not the full code. You must have more. Including the function you have this code in.

Here is the full code

#include "MainScene.h"
#include "MyBodyParser.h"
#include "SimpleAudioEngine.h"

USING_NS_CC;

Scene* MainScene::createScene()
{
    auto scene = Scene::createWithPhysics();
    scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
    
    auto layer = MainScene::create();
    layer->setPhysicsWorld(scene->getPhysicsWorld());
    
    scene->addChild(layer);
    
    return scene;
}

bool MainScene::init()
{
    if ( !Scene::init() )
    {
        return false;
    }
    
    LayerColor *_bgColor = LayerColor::create(Color4B(0, 191, 255,230));
    this->addChild(_bgColor, -10);
    
    auto visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    
    auto listener = EventListenerTouchOneByOne::create();
    listener->onTouchBegan = CC_CALLBACK_2(MainScene::onTouchBegan, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
    
    auto contactListener = EventListenerPhysicsContact::create();
    contactListener->onContactBegin = CC_CALLBACK_1(MainScene::onContactBegin, this);
    this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);
    
    auto edgeNode = Node::create();
    edgeNode->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2));
    
    auto edgeBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);
    
    edgeNode->setPhysicsBody(edgeBody);
    
    this->addChild(edgeNode);
    
    {
        auto circle = Sprite::create("circle.png");
        circle->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height - 80));
        circle->runAction(RepeatForever::create(RotateBy::create(3.0f, 360)));
        
        MyBodyParser::getInstance()->parseJsonFile("circle.json");
        
        auto circleBody = MyBodyParser::getInstance()->bodyFormJson(circle, "circle", PhysicsMaterial(0, 0, 1));
        
        if(circleBody != nullptr) {
            circleBody->setDynamic(false);
            circle->setPhysicsBody(circleBody);
        }
        
        this->addChild(circle);
    }
    
    {
        auto apple = Sprite::create("apple.png");
        apple->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height - 80));
        
        auto appleBody = PhysicsBody::createCircle(apple->getContentSize().width / 2, PhysicsMaterial(0, 0, 1));
        appleBody->setCollisionBitmask(1);
        appleBody->setContactTestBitmask(true);
        
        if(appleBody != nullptr) {
            appleBody->setDynamic(false);
            apple->setPhysicsBody(appleBody);
        }
        
        this->addChild(apple);
    }
    
    {
        auto cloud1 = Sprite::create("cloud.png");
        cloud1->setPosition(Vec2(origin.x + 25, origin.y + visibleSize.height / 2));
        
        this->addChild(cloud1);
        
        auto cloud2 = Sprite::create("cloud.png");
        cloud2->setPosition(Vec2(origin.x + 145, origin.y + 300));
        
        this->addChild(cloud2);
    }
    
    {
        arrow = Sprite::create("arrow.png");
        arrow->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 6));
        
        arrowBody = PhysicsBody::createBox(arrow->getContentSize(), PhysicsMaterial(0, 0, 0));
        arrowBody->setCollisionBitmask(2);
        arrowBody->setContactTestBitmask(true);
        arrowBody->setDynamic(false);
        
        arrow->setPhysicsBody(arrowBody);
        
        this->addChild(arrow);
    }
    
    return true;
}

void MainScene::throwArrow() {
    auto visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    
    action = MoveBy::create(3.0f, Vec2(0, origin.y + visibleSize.height));
    arrow->runAction(action);
}

bool MainScene::onContactBegin(cocos2d::PhysicsContact &contact) {
    PhysicsBody *a = contact.getShapeA()->getBody();
    PhysicsBody *b = contact.getShapeB()->getBody();
    
    if (1 == a->getCollisionBitmask() && 2 == b->getCollisionBitmask() || 2 == a->getCollisionBitmask() && 1 == b->getCollisionBitmask()) {
        arrowBody->setDynamic(false);
    }
}

bool MainScene::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event) {
    throwArrow();
    arrowBody->setDynamic(true);
}

void MainScene::onTouchDragged(cocos2d::Touch *touch, cocos2d::Event *event) {
    
}

void MainScene::onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event) {

}

Ok I see. I do things a bit differently than you do.

Why all of the local scope insolation inside init()? That seems like a problem to me.

It still give to me this error: Aborting due to Chipmunk error: This operation cannot be done safely during a call to cpSpaceStep() or during a query. Put these calls into a post-step callback.

Did you get rid of the local scope?

What is meant by local scope? I did not fully understand. Can you explain via code file please. This is my full .cpp file

#include "MainScene.h"
#include "MyBodyParser.h"
#include "SimpleAudioEngine.h"

USING_NS_CC;

Scene* MainScene::createScene()
{
    auto scene = Scene::createWithPhysics();
    scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_NONE);
    
    auto layer = MainScene::create();
    layer->setPhysicsWorld(scene->getPhysicsWorld());
    
    scene->addChild(layer);
    
    return scene;
}

bool MainScene::init()
{
    if ( !Scene::init() )
    {
        return false;
    }
    
    LayerColor *_bgColor = LayerColor::create(Color4B(0, 191, 255,230));
    this->addChild(_bgColor, -10);
    
    auto visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    
    auto listener = EventListenerTouchOneByOne::create();
    listener->onTouchBegan = CC_CALLBACK_2(MainScene::onTouchBegan, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
    
    auto contactListener = EventListenerPhysicsContact::create();
    contactListener->onContactBegin = CC_CALLBACK_1(MainScene::onContactBegin, this);
    this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);
    
    auto edgeNode = Node::create();
    edgeNode->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2));
    
    auto edgeBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);
    
    edgeNode->setPhysicsBody(edgeBody);
    
    this->addChild(edgeNode);
    
    auto circle = Sprite::create("circle.png");
    circle->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height - 80));
    circle->runAction(RepeatForever::create(RotateBy::create(3.0f, 360)));
    
    MyBodyParser::getInstance()->parseJsonFile("circle.json");
    
    auto circleBody = MyBodyParser::getInstance()->bodyFormJson(circle, "circle", PhysicsMaterial(0, 0, 1));
    
    if(circleBody != nullptr) {
        circleBody->setDynamic(false);
        circle->setPhysicsBody(circleBody);
    }
    
    //this->addChild(circle);
    
    auto apple = Sprite::create("apple.png");
    apple->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height - 80));
    
    auto appleBody = PhysicsBody::createCircle(apple->getContentSize().width / 2, PhysicsMaterial(0, 0, 0));
    appleBody->setCollisionBitmask(1);
    appleBody->setContactTestBitmask(true);
    
    appleBody->setDynamic(false);
    apple->setPhysicsBody(appleBody);
        
    this->addChild(apple);
    
    auto cloud1 = Sprite::create("cloud.png");
    cloud1->setPosition(Vec2(origin.x + 25, origin.y + visibleSize.height / 2));
        
    this->addChild(cloud1);
        
    auto cloud2 = Sprite::create("cloud.png");
    cloud2->setPosition(Vec2(origin.x + 145, origin.y + 300));
        
    this->addChild(cloud2);
    
    arrow = Sprite::create("arrow.png");
    arrow->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 6));
    
    arrowBody = PhysicsBody::createBox(arrow->getContentSize(), PhysicsMaterial(0, 0, 0));
    arrowBody->setCollisionBitmask(2);
    arrowBody->setContactTestBitmask(true);
    arrowBody->setDynamic(false);
    arrow->setPhysicsBody(arrowBody);
    
    this->addChild(arrow);
    
    return true;
}

bool MainScene::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event) {
    action = MoveBy::create(1.0f, Vec2(0, 200));
    arrowBody->setDynamic(true);
    arrow->runAction(action);
    
    return true;
}

bool MainScene::onContactBegin(cocos2d::PhysicsContact &contact) {
    PhysicsBody *a = contact.getShapeA()->getBody();
    PhysicsBody *b = contact.getShapeB()->getBody();
    
    if ( (1 == a->getCollisionBitmask() && 2 == b->getCollisionBitmask() ) || ( 2 == a->getCollisionBitmask() && 1 == b->getCollisionBitmask() ) ) {
        arrowBody->setDynamic(false);
    }
    
    return true;
}

and this is my header file:
#ifndef MAIN_SCENE_H
#define MAIN_SCENE_H

#include "cocos2d.h"
#include "MyBodyParser.h"

class MainScene : public cocos2d::Scene
{
public:
    static cocos2d::Scene* createScene();
    
    virtual bool init();
    
    CREATE_FUNC(MainScene);
    
    bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event);
    
    cocos2d::Sprite *arrow;
    cocos2d::MoveBy *action;
    cocos2d::PhysicsBody *arrowBody;
    
    cocos2d::PhysicsWorld *physicsWorld;
    
    void setPhysicsWorld(cocos2d::PhysicsWorld *world) {physicsWorld = world;};
    
    bool onContactBegin(cocos2d::PhysicsContact &contact);
    
};

#endif // __MAIN_SCENE_H__

The error is pretty clear. You are trying to change the state of a physics object within the context of a physics step update, which is not allowed. Instead of calling arrow->setDynamic(false), set some local (member variable in your MainScene) boolean value, e.g. isArrowActive.

Then, in the scene’s update() method, you can check if the state of the local variable has changed, then call arrow->setDynamic() as appropriate. Make sense?

1 Like

OK Thanks for your reply!