cocos2dx物理引擎疑问

我想要制作合成大西瓜的游戏
当两个物体碰撞时会调用onContactBegin函数
在函数中,我把两个碰撞的物体删掉
然后新建一个精灵,并且给精灵添加上physicsBody
把位置设置在碰撞的位置
但是,运行时新添加的精灵总是会出现在屏幕左下角

bool CollisionScene::onContactBegin(PhysicsContact& contact)
{
	auto nodeA = contact.getShapeA()->getBody()->getNode();
	auto nodeB = contact.getShapeB()->getBody()->getNode();

	if (nodeA && nodeB)
	{
		Vec2 _pos(nodeA->getPosition());
		nodeA->removeFromParent();
		nodeB->removeFromParent();
		auto physicsBody = PhysicsBody::createBox(Size(65.0f, 81.0f),
			PhysicsMaterial(0.1f, 1.0f, 0.0f));
		physicsBody->setDynamic(true);
		physicsBody->setGravityEnable(true);
		physicsBody->setContactTestBitmask(0xFFFFFFFF);
		auto sprite = Sprite::create("blueSprite.png");
		sprite->setPosition(_pos);
		sprite->setPhysicsBody(physicsBody);
		this->addChild(sprite);
	}

	//bodies can collide
	return true;
}

找了好几天了,依然不知道哪里错了,希望各位大佬帮忙!

setPosition是设置节点的位置,物理世界的坐标没有设置啊,默认:0,0

能够具体说一下怎么改吗?非常感谢!

原生的我没有看具体代码,但小游戏/H5有 rigid有syncPosition(), 把节点世界坐标同步到 box2d 刚体的坐标上。

我也在找接口,目前我是通过延迟一帧实现的,可能相同位置有刚体,引擎计算后发现无效,所以放在左下角了。

以前做的笔记:仅供参考 :thinking:

onContactBegin 中添加刚体导致节点信息被覆盖的问题

- 节点信息丢失,被物理世界同步回来的数据覆盖

原因分析

beforeSimulation #1 同步节点信息到刚体

cpSpaceStep
	- 触发碰撞事件
	- 执行回调onContactBegin
//
- 如果在此处添加新的刚体
	- 会导致刚体原始信息没有同步到物理世界. 没有执行beforeSimulation
	- afterSimulation会同步刚体信息到节点,而新刚体的刚体信息是默认的。还没有经过任何同步。
		- 会被覆盖掉,丢失了原始节点信息
		- 覆盖为空
		
afterSimulation #2 同步刚体位置/旋转信息到节点

解决方案

// 在下一帧再执行新增刚体的操作
ScheduleUtil::onNextFrame(this,[this](float dt){
	auto& endPos=_attackMonster->convertToWorldSpace(Vec2::ZERO);
	_gun->fire(endPos);//发射子弹
});

cpSpaceStep

// 物理世界步进
// - 刚体发生碰撞时会触发事件,调用回调等collisionBeginCallbackFunc
// 	- listener->onContactBegin=[](PhysicsContact& contact){
// P:\@git\game_test\__cocos2dx\physics\cocos\CCPhysicsWorld\Event事件\setPreUpdateCallback 更新事件.cpp

void PhysicsWorld::update(float delta, bool userCall)
	cpSpaceStep(_cpSpace, delta);

// 事件回调
cpCollisionHandler *handler = cpSpaceAddDefaultCollisionHandler(_cpSpace);
handler->userData = this;
handler->beginFunc = (cpCollisionBeginFunc)PhysicsWorldCallback::collisionBeginCallbackFunc;
handler->preSolveFunc = (cpCollisionPreSolveFunc)PhysicsWorldCallback::collisionPreSolveCallbackFunc;
handler->postSolveFunc = (cpCollisionPostSolveFunc)PhysicsWorldCallback::collisionPostSolveCallbackFunc;
handler->separateFunc = (cpCollisionSeparateFunc)PhysicsWorldCallback::collisionSeparateCallbackFunc;


void PhysicsWorld::update(float delta, bool userCall)
{

    if(_preUpdateCallback) _preUpdateCallback(); //fix #11154
	
	/// #1 同步节点信息到刚体
    auto sceneToWorldTransform = _scene->getNodeToParentTransform();
    beforeSimulation(_scene, sceneToWorldTransform, 1.f, 1.f, 0.f);
	
	...
	// 物理世界步进
	// - 刚体发生碰撞时会触发事件,调用回调等collisionBeginCallbackFunc
	// 	- listener->onContactBegin=[](PhysicsContact& contact){
	if (userCall)
    {
		#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
				cpSpaceStep(_cpSpace, delta);
		#else
				cpHastySpaceStep(_cpSpace, delta);
		#endif
    }
	...
	
    // Update physics position, should loop as the same sequence as node tree.
    // PhysicsWorld::afterSimulation() will depend on the sequence.
	// 更新物理位置,应该按照与节点树相同的顺序循环。
    // PhysicsWorld::afterSimulation() 将取决于序列。
	
	/// #2 同步刚体位置/旋转信息到节点
    afterSimulation(_scene, sceneToWorldTransform, 0.f);

    if(_postUpdateCallback) _postUpdateCallback(); //fix #11154
}

肯定是位置的原因,你输出位置就知道了,我怀疑是还有其他物体碰撞导致位置不对