在Xcode中使用c ++在cocos2dx中动态生成Box2d体

时间:2014-03-25 04:52:49

标签: cocos2d-x

我是cocos2dx的新开发人员。我正在开发一个游戏,我正在使用通过物理编辑器加载的box2d主体。在游戏关卡中有20多个主体使用,我正在分开与它们相连的单独精灵的身体和类似的身体在其他级别使用,并且在游戏中有50个级别,对于每个级别,我已经制作了单独的类并再次制作b2body加载功能,所有代码都正常工作但是我只想制作一个通用函数来加载一个类中的实体,这样我就可以在所有级别中使用相同的b2body加载函数。此外,我必须在触摸精灵时销毁特定的主体和精灵

//Sprites:
rect_sprite1=CCSprite::create("rect1.png");
rect_sprite1->setScaleX(rX);
rect_sprite1->setScaleY(rY);
this->addChild(rect_sprite1,1);

rect_sprite2=CCSprite::create("rect2.png");
rect_sprite2->setScaleX(rX);
rect_sprite2->setScaleY(rY);
this->addChild(rect_sprite2,1);

rect_sprite3=CCSprite::create("circle.png");
rect_sprite3->setScale(rZ);
this->addChild(rect_sprite3,1);

GB2ShapeCache::sharedGB2ShapeCache()->addShapesWithFile("obs.plist");

//body loading function

void Level1::addNewSpriteWithCoords()
{
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
b2BodyDef bodyDef1;
bodyDef1.type=b2_dynamicBody;
bodyDef1.position.Set((winSize.width*0.38)/PTM_RATIO,(winSize.height*0.4) /PTM_RATIO);
bodyDef1.userData = rect_sprite1;
body1 = (MyPhysicsBody*)world->CreateBody(&bodyDef1);
body1->setTypeFlag(7);
// add the fixture definitions to the body
GB2ShapeCache *sc1 = GB2ShapeCache::sharedGB2ShapeCache();
sc1->addFixturesToBody(body1,"rect1", rect_sprite1);
rect_sprite1->setAnchorPoint(sc1->anchorPointForShape("rect1"));

b2BodyDef bodyDef2;
bodyDef2.type=b2_dynamicBody;
bodyDef2.position.Set((winSize.width*0.62)/PTM_RATIO,  
(winSize.height*0.4)/PTM_RATIO);
bodyDef2.userData = rect_sprite2;
body2 = (MyPhysicsBody*)world->CreateBody(&bodyDef2);
body2->setTypeFlag(7);
// add the fixture definitions to the body
GB2ShapeCache *sc2 = GB2ShapeCache::sharedGB2ShapeCache();
sc2->addFixturesToBody(body2,"rect2", rect_sprite2);
rect_sprite2->setAnchorPoint(sc2->anchorPointForShape("rect2"));

b2BodyDef bodyDef3;
bodyDef3.type=b2_dynamicBody;
bodyDef3.position.Set((winSize.width*0.5)/PTM_RATIO, (winSize.height*0.23)/PTM_RATIO);
bodyDef3.userData = rect_sprite3;
body3 = (MyPhysicsBody*)world->CreateBody(&bodyDef3);
body3->setTypeFlag(7);
// add the fixture definitions to the body
GB2ShapeCache *sc3 = GB2ShapeCache::sharedGB2ShapeCache();
sc3->addFixturesToBody(body3,"circle", rect_sprite3);
rect_sprite3->setAnchorPoint(sc3->anchorPointForShape("circle"));
}
void Level1::ccTouchesBegan(cocos2d::CCSet* touches, cocos2d::CCEvent* event)
{

if(box->containsPoint(touchPoint))
                {
                    this->removeChild(((CCSprite*)rect),true);
                    if(((CCSprite*)rect)==rect_sprite1)
                    {
                        rect_sprite1=NULL;
                        world->DestroyBody(body1);
                        Utils::setCount(Utils::getCount()-1);

                    }
                    if(((CCSprite*)rect)==rect_sprite2)
                    {
                        rect_sprite2=NULL;
                        world->DestroyBody(body2);
                        Utils::setCount(Utils::getCount()-1);
                    }


                    if(((CCSprite*)rect)==rect_sprite3)
                    {
                        rect_sprite3=NULL;
                        world->DestroyBody(body3);
                        Utils::setCount(Utils::getCount()-1);

                    }

} 

同样地,我正在为其他级别做。 如果有人知道,请建议。谢谢

1 个答案:

答案 0 :(得分:0)

这似乎更像是"我应该使用什么设计模式?"而不是加载代码的具体问题。

一般来说,当我想创建"实体"这需要一个物理体,我使用一个包含Box2D体的基类作为其成员之一。基类是主体的容器(分配给它),并且当实体被销毁时负责销毁主体(将其从Box2D世界中移除)。

派生类可以从Box2D形状缓存加载正文。最好通过一个例子来说明。我正在进行一场游戏,在那里我有一群不同形状的小行星在太阳下盘旋。这是一个屏幕截图:

enter image description here

基类Entity包含主体并在销毁实体时销毁它:

class Entity : public HasFlags
{
public:

   enum
   {
      DEFAULT_ENTITY_ID = -1,
   };
private:
   uint32 _ID;
   // Every entity has one "main" body which it
   // controls in some way.  Or not.
   b2Body* _body;
   // Every entity has a scale size from 1 to 100.
   // This maps on to the meters size of 0.1 to 10
   // in the physics engine.
   uint32 _scale;

protected:
   void SetScale(uint32 value)
   {
      assert(value >= 1);
      assert(value <= 100);
      _scale = value;
   }

public:

   void SetBody(b2Body* body)
   {
      assert(_body == NULL);
      if(_body != NULL)
      {
         CCLOG("BODY SHOULD BE NULL BEFORE ASSIGNING");
         _body->GetWorld()->DestroyBody(_body);
         _body = NULL;
      }
      _body = body;
      if(body != NULL)
      {
         _body->SetUserData(this);
         for (b2Fixture* f = _body->GetFixtureList(); f; f = f->GetNext())
         {
            f->SetUserData(this);
         }
      }
   }



   inline void SetID(uint32 ID)
   {
      _ID = ID;
   }

   inline uint32 GetID() const
   {
      return _ID;
   }

   virtual string ToString(bool updateDescription = false)
   {
      string descr = "ID: ";
      descr += _ID;
      descr += "Flags: ";
      if(IsFlagSet(HF_IS_GRAPH_SENSOR))
         descr += "IS_FLAG_SENSOR ";
      return descr;
   }


   Entity() :
   _ID(DEFAULT_ENTITY_ID),
   _body(NULL),
   _scale(1)
   {
   }

   Entity(uint32 flags, uint32 scale) :
   HasFlags(flags),
   _ID(DEFAULT_ENTITY_ID),
   _body(NULL),
   _scale(scale)
   {

   }

   virtual void Update()
   {

   }

   virtual void UpdateDisplay()
   {

   }

   virtual ~Entity()
   {
      if(_body != NULL)
      {
         _body->GetWorld()->DestroyBody(_body);
      }
   }

   inline static float32 ScaleToMeters(uint32 scale)
   {
      return 0.1*scale;
   }

   inline Body* GetBody()
   {
      return _body;
   }

   inline const Body* GetBody() const
   {
      return _body;
   }

   inline uint32 GetScale()
   {
      return _scale;
   }

   inline float32 GetSizeMeters()
   {
      return ScaleToMeters(_scale);
   }
};

小行星类本身负责装载几种不同的小行星&#34;形状缓存中的形状。然而,所有小行星都具有使它们围绕屏幕中心移动的共同逻辑。他们连接了一个绳索接头,更新(...)功能增加了一些&#34;旋转&#34;他们围绕中心旋转:

 class Asteroid : public Entity
    {
    private:
       b2Fixture* _hull;
       Vec2 _anchor;
       CCSprite* _sprite;
       float32 _targetRadius;
    public:
       // Some getters to help us out.
       b2Fixture& GetHullFixture() const { return *_hull; }
       float32 GetTargetRadius() { return _targetRadius; }
       CCSprite* GetSprite() { return _sprite; }


       void UpdateDisplay()
       {
          // Update the sprite position and orientation.
          CCPoint pixel = Viewport::Instance().Convert(GetBody()->GetPosition());
          _sprite->setPosition(pixel);
          _sprite->setRotation(-CC_RADIANS_TO_DEGREES(GetBody()->GetAngle()));
       }

       virtual void Update()
       {
          Body* body = GetBody();

          Vec2 vRadius = body->GetPosition();
          Vec2 vTangent = vRadius.Skew();

          vTangent.Normalize();
          vRadius.Normalize();


          // If it is not moving...give it some spin.
          if(fabs(vTangent.Dot(body->GetLinearVelocity())) < 1)
          {
             body->SetLinearDamping(0.001);
             body->ApplyForceToCenter(body->GetMass()*1.5*vTangent);
             body->ApplyForce(vRadius,body->GetMass()*0.05*vRadius);
          }
          else
          {
             body->SetLinearDamping(0.05);
          }
       }

       ~Asteroid()
       {

       }

       Asteroid() :
       Entity(HF_CAN_MOVE | HF_UPDATE_PRIO_5,50)
       {

       }

       bool Create(b2World& world, const string& shapeName,const Vec2& position, float32 targetRadius)
       {
          _targetRadius = targetRadius;
          _anchor = position;

          string str = shapeName;
          str += ".png";
          _sprite = CCSprite::createWithSpriteFrameName(str.c_str());
          _sprite->setTag((int)this);
          _sprite->setAnchorPoint(ccp(0.5,0.5));

          //      _sprite->setVisible(false);

          b2BodyDef bodyDef;
          bodyDef.position = position;
          bodyDef.type = b2_dynamicBody;
          Body* body = world.CreateBody(&bodyDef);
          assert(body != NULL);

          // Add the polygons to the body.
          Box2DShapeCache::instance().addFixturesToBody(body, shapeName, GetSizeMeters());

          SetBody(body);      
          return true;
       }

    };

从场景中的加载代码调用Asteroid的Create(...)函数,该函数很容易成为带有形状名称的.csv文件。它实际上重复使用了几次名称(只有大约10个小行星形状)。

您会注意到Asteroid也有一个与之关联的CCSprite。并非所有实体都有精灵,但有些实体。我可以为这种情况创建一个Entity-Derived类(EntityWithSprite),以便也可以管理sprite,但我尽量避免使用太多的嵌套类。我本可以把它放到基类中,并且可能仍然存在。无论如何,小行星包含自己的精灵并从SpriteCache加载它们。它们在代码的不同部分更新(这里不相关,但如果您感到好奇,我很乐意回答有关它的问题)。

注意:这是更大代码库的一部分,并且有一些功能,如缩放,相机,图形/路径查找以及代码库中的许多其他好东西。随意使用您认为有用的东西。

您可以在github找到所有(iOS)代码,并在我的网站here上发布视频和教程。