cocos2dx 3.x使用Box 2 d


よく知られているcocs 2 dx 3.xにはPhysicsのパッケージがあり、chipmunkとbox 2 dを同時にパッケージしたいのかもしれませんが、なぜchipmunkだけが実現したのかbox 2 dは関係ありません.
最近試してみましたが、chipmunkの問題は多く、PhysicsBodyの速度が十分速い限り、staticBodyやEdgeと衝突しても貫通する可能性があり、貫通していなくてもbodyに速度を設定し続けると、衝突を無視して堂々と着用します.
それからTestCppのbox 2 dに関するコードを見てみると、box 2 dの表現が明らかに良いことがわかりました.
cococos 2 dはcococos 2 d::PhysicsSpriteを実現したが、その実現には問題がある.
  • は、各PhysicsSpriteにおいてDirector::EVENT_AFTER_UPDATEイベントは、Box 2 dワールドとcococosワールドの座標を同期させるが、cococos 2 d::Node::visitで同期
  • を完全に行うことができる.
  • 同期座標では親子ノードの関係はまったく考慮されず、すべてのPhysicsSpriteがSceneに直接接続されている場合にのみ、
  • が正常に動作する.
  • ゲームシーンにui、main、backgroundなど相対的に変位する階層ノードがある場合、座標同期を行う際の基準ノードはmainノードであるべきであり、box 2 dのdebugモードを描く場合、modelViewマトリクスもmainノード
  • に基づいている必要がある.
    だから自分で1つの簡単なbox 2 dに対するパッケージBox 2 dNodeを実現しました:public Node
  • Box 2 d b 2 Worldを初期化し、基準ノードとして設定し、基準ノードリスニングDirector::EVENT_AFTER_UPDATEはb 2 World::Stepを行い、draw時にレンダリングキューにカスタムイベントを挿入してbox 2 dのdebug情報を描画します.
  • Box 2 d b 2 Bodyを作成し、setPositionとsetRotationでcococos座標系をbox 2 d座標系に同期し、visitでbox 2 d座標系をcocos座標系に同期することができます.

  • キーコードは次のとおりです.
    基準ノードb 2 Worldに対してStepを行う
    	void Box2dNode::onEnter()
    	{
    		Node::onEnter();
    
    		if (m_body)
    		{
    			m_body->SetActive(true);
    		}
    		if (m_is_box2d_root)
    		{
    			//      afterUpdate  ,  step box2d
    			s_after_update_listener = Director::getInstance()->getEventDispatcher()->addCustomEventListener(Director::EVENT_AFTER_UPDATE, std::bind(&Box2dNode::stepBox2d, this, std::placeholders::_1));
    			s_after_update_listener->retain();
    		}
    
    	}
    	void Box2dNode::stepBox2d(EventCustom *event)
    	{
    		Director* director = Director::getInstance();
    		s_world->Step(1 / 60.0f, 1, 1);
    	}

    データムノード描画box 2 d debug情報
    	void Box2dNode::draw(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t flags)
    	{
    		Node::draw(renderer, transform, flags);
    
    
    		//                renderCommand
    		if (m_is_box2d_root != 0)
    		{
    			if (s_draw_command == 0)
    			{
    				s_draw_command = new CustomCommand();
    			}
    			s_draw_command->init(10, transform, flags);
    			s_draw_command->func = CC_CALLBACK_0(Box2dNode::onDraw, this, transform, flags);
    			renderer->addCommand(s_draw_command);
    		}
    	}
    
    
    	void Box2dNode::onDraw(const Mat4 &transform, uint32_t flags)
    	{
    		Director* director = Director::getInstance();
    		CCASSERT(nullptr != director, "Director is null when seting matrix stack");
    		director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    		director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform);
    
    		GL::enableVertexAttribs(cocos2d::GL::VERTEX_ATTRIB_FLAG_POSITION);
    
    		s_world->DrawDebugData();
    
    		CHECK_GL_ERROR_DEBUG();
    
    		director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
    	}
    

    座標系同期:
    	void Box2dNode::setPosition(float x, float y)
    	{
    		if (m_body)
    		{
    			_position.x = x;
    			_position.y = y;
    
    			//              box2d
    			Node* parent = this->getParent();
    			if (parent)
    			{
    				AffineTransform mat = getAffineTransformToWorldRoot(parent);
    				mat = AffineTransformTranslate(mat, x, y);
    
    				x = mat.tx;
    				y = mat.ty;
    			}
    			float angle = m_body->GetAngle();
    			m_body->SetTransform(b2Vec2(x / PTM_RATIO, y / PTM_RATIO), angle);
    		}
    		else
    		{
    			Node::setPosition(x, y);
    		}
    	}
    
    	void Box2dNode::setRotation(float fRotation)
    	{
    		if (m_body)
    		{
    			_rotationZ_X = _rotationZ_Y = fRotation;
    			updateRotationQuat();
    
    			//              boxbody
    			b2Vec2 p = m_body->GetPosition();
    			float radians = CC_DEGREES_TO_RADIANS(fRotation);
    			Node* parent = this->getParent();
    			if (parent)
    			{
    				AffineTransform mat = getAffineTransformToWorldRoot(parent);
    				mat = AffineTransformRotate(mat, radians);
    
    				radians = acosf(mat.a);
    			}
    			m_body->SetTransform(p, radians);
    		}
    		else
    		{
    			Node::setRotation(fRotation);
    		}
    	}
    
    
    	void Box2dNode::visit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags)
    	{
    		//  box2d          transform
    		if (m_body)
    		{
    			b2Vec2 pos = m_body->GetPosition();
    			float radians = m_body->GetAngle();
    			AffineTransform world_xy = AffineTransformTranslate(AffineTransform::IDENTITY, pos.x * PTM_RATIO, pos.y * PTM_RATIO);
    			AffineTransform world_rot = AffineTransformRotate(AffineTransform::IDENTITY, radians);
    			AffineTransform world_trans = AffineTransformConcat(world_rot, world_xy);
    			Node* parent = this->getParent();
    			if (parent)
    			{
    				AffineTransform parent_world = AffineTransformInvert(getAffineTransformToWorldRoot(parent));
    				AffineTransform local_trans = AffineTransformConcat(world_trans, parent_world);
    
    				if (!_anchorPointInPoints.isZero())
    				{
    					local_trans = AffineTransformTranslate(local_trans, -_anchorPointInPoints.x, -_anchorPointInPoints.y);
    				}
    
    				_position.x = local_trans.tx;
    				_position.y = local_trans.ty;
    				_rotationZ_X = _rotationZ_Y = CC_RADIANS_TO_DEGREES(acosf(local_trans.a));
    
    				CGAffineToGL(local_trans, _transform.m);
    				_transformDirty = false;
    				_inverseDirty = true;
    				_transformUpdated = true;
    			}
    		}
    
    		//---------------------------------------------------------------
    		Node::visit(renderer, parentTransform, parentFlags);
    	}