当前位置:   article > 正文

cocos2d-x box2d Demo讲解

cocos box2d世界模拟

勤奋努力,持之以恒!

核心概念

Box2D 中有一些基本的对象,这里我们先做一个简要的定义,在随后的文档里会有更详细的描述。

刚体(rigid body)

一块十分坚硬的物质,它上面的任何两点之间的距离都是完全不变的。它们就像钻石那样坚硬。在后面的讨论中,我们用物体(body)来代替刚体。

形状(shape)

一块严格依附于物体(body)的 2D 碰撞几何结构(collision geometry)。形状具有摩擦(friction)和恢复(restitution)的材料性质。

约束(constraint)

一个约束(constraint)就是消除物体自由度的物理连接。在 2D 中,一个物体有 3 个自由度。如果我们把一个物体钉在墙上(像摆锤那样),那我们就把它约束到了墙上。这样,此物体就只能绕着这个钉子旋转,所以这个约束消除了它 2 个自由度。

接触约束(contact constraint)

一个防止刚体穿透,以及用于模拟摩擦(friction)和恢复(restitution)的特殊约束。你永远都不必创建一个接触约束,它们会自动被 Box2D 创建。

关节(joint)

它是一种用于把两个或多个物体固定到一起的约束。Box2D 支持的关节类型有:旋转,棱柱,距离等等。关节可以支持限制(limits)和马达(motors)。

关节限制(joint limit)

一个关节限制(joint limit)限定了一个关节的运动范围。例如人类的胳膊肘只能做某一范围角度的运动。

关节马达(joint motor)

一个关节马达能依照关节的自由度来驱动所连接的物体。例如,你可以使用一个马达来驱动一个肘的旋转。

世界(world)

一个物理世界就是物体,形状和约束相互作用的集合。Box2D 支持创建多个世界,但这通常是不必要的

  1. //
  2. // HelloWorldScene.cpp
  3. // Box2d
  4. //
  5. // Created by XiangZi on 14-6-23.
  6. // Copyright __MyCompanyName__ 2014年. All rights reserved.
  7. //
  8. #include "HelloWorldScene.h"
  9. //单位:Box2D中距离以米为单位,质量以公斤为单位,时间以秒为单位。
  10. //屏幕的宽度和高度值除以一个名为 PTM_RATIO 的常量,把像素值转换成了以米为单位来计算长度。
  11. #define PTM_RATIO 32 //PTM_RATIO用于定义32个像素在Box2D世界中等同于1米。
  12. enum {
  13. kTagParentNode = 1,
  14. };
  15. PhysicsSprite::PhysicsSprite()
  16. : m_pBody(NULL)
  17. {
  18. }
  19. void PhysicsSprite::setPhysicsBody(b2Body * body)
  20. {
  21. m_pBody = body;
  22. }
  23. //重写isDirty方法,返回YES,目的是让每次layer的update调用后重新绘制PhysicsSprite精灵。
  24. bool PhysicsSprite::isDirty(void)
  25. {
  26. return true;
  27. }
  28. /*
  29. 重写精灵的矩阵变换方法nodeToParentTransform,模板提供的这个实现,能改变精灵的位置和角度。
  30. 我们会看到,在update函数中,调用了Box2D的Step方法,这个方法根据时间流逝计算出每个刚体的新位置和角度,
  31. 然后在这里被使用最终达到精灵移动旋转的目的。
  32. */
  33. CCAffineTransform PhysicsSprite::nodeToParentTransform(void)
  34. {
  35. b2Vec2 pos = m_pBody->GetPosition();
  36. float x = pos.x * PTM_RATIO;
  37. float y = pos.y * PTM_RATIO;
  38. if ( isIgnoreAnchorPointForPosition() ) {
  39. x += m_obAnchorPointInPoints.x;
  40. y += m_obAnchorPointInPoints.y;
  41. }
  42. // Make matrix
  43. float radians = m_pBody->GetAngle();
  44. float c = cosf(radians);
  45. float s = sinf(radians);
  46. if( ! m_obAnchorPointInPoints.equals(CCPointZero) ){
  47. x += c*-m_obAnchorPointInPoints.x + -s*-m_obAnchorPointInPoints.y;
  48. y += s*-m_obAnchorPointInPoints.x + c*-m_obAnchorPointInPoints.y;
  49. }
  50. // Rot, Translate Matrix
  51. m_sTransform = CCAffineTransformMake( c, s,
  52. -s, c,
  53. x, y );
  54. return m_sTransform;
  55. }
  56. HelloWorld::HelloWorld()
  57. {
  58. setTouchEnabled( true );
  59. setAccelerometerEnabled( true );
  60. CCSize s = CCDirector::sharedDirector()->getWinSize();
  61. // init physics
  62. this->initPhysics();
  63. CCSpriteBatchNode *parent = CCSpriteBatchNode::create("blocks.png", 100);
  64. m_pSpriteTexture = parent->getTexture();
  65. addChild(parent, 0, kTagParentNode);
  66. addNewSpriteAtPosition(ccp(s.width/2, s.height/2));
  67. CCLabelTTF *label = CCLabelTTF::create("Tap screen", "Marker Felt", 32);
  68. addChild(label, 0);
  69. label->setColor(ccc3(0,0,255));
  70. label->setPosition(ccp( s.width/2, s.height-50));
  71. scheduleUpdate();
  72. }
  73. HelloWorld::~HelloWorld()
  74. {
  75. delete world;
  76. world = NULL;
  77. }
  78. void HelloWorld::initPhysics()
  79. {
  80. CCSize s = CCDirector::sharedDirector()->getWinSize();
  81. b2Vec2 gravity;
  82. gravity.Set(0.0f, -10.0f);
  83. //对Box2D世界进行初始化
  84. world = new b2World(gravity);
  85. /*
  86. 会“睡眠”的动态刚体:当施加到某个刚体上的力量小于临界值一段时间以后,这个刚体将会进入“睡眠”状态。
  87. 换句话说,如果某个刚体移动或者旋转的很慢或者根本不在动的话,物理引擎将会把它标记为“睡眠”状态,
  88. 不再对其施加力量,直到新的力量施加到刚体上让其再次移动或者旋转。通过把一些刚体标记为“睡眠”状态,
  89. 物理引擎可以省下很多时间。除非你游戏中的所有动态刚体处于持续的运动中,否则应该把
  90. SetAllowSleeping变量设置为true。
  91. */
  92. world->SetAllowSleeping(true);
  93. //设置检测连续碰撞
  94. world->SetContinuousPhysics(true);
  95. //1.创建一个body定义结构体,用以指定body的初始属性,比如位置或者速度。
  96. b2BodyDef groundBodyDef;
  97. groundBodyDef.position.Set(0, 0);
  98. //2.调用world对象来创建一个body对象
  99. b2Body* groundBody = world->CreateBody(&groundBodyDef);
  100. //3.为body对象定义一个shape,用以指定想要仿真的物体的几何形状。
  101. b2EdgeShape groundBox;
  102. //4.创建一个fixture定义,同时设置之前创建好的shape为fixture的一个属性,并且设置其它的属性,比如质量或者摩擦力。
  103. // bottom
  104. groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO,0));
  105. groundBody->CreateFixture(&groundBox,0);
  106. // top
  107. groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
  108. groundBody->CreateFixture(&groundBox,0);
  109. // left
  110. groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));
  111. groundBody->CreateFixture(&groundBox,0);
  112. // right
  113. groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,0));
  114. groundBody->CreateFixture(&groundBox,0);
  115. }
  116. void HelloWorld::draw()
  117. {
  118. //
  119. // IMPORTANT:
  120. // This is only for debug purposes
  121. // It is recommend to disable it
  122. CCLayer::draw();
  123. ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
  124. kmGLPushMatrix();
  125. world->DrawDebugData();
  126. kmGLPopMatrix();
  127. }
  128. void HelloWorld::addNewSpriteAtPosition(CCPoint p)
  129. {
  130. CCNode* parent = getChildByTag(kTagParentNode);
  131. //有一个64x64的精灵表有4种不同的32x32的图像,只是随机挑选其中一个图像。
  132. int idx = (CCRANDOM_0_1() > .5 ? 0:1);
  133. int idy = (CCRANDOM_0_1() > .5 ? 0:1);
  134. PhysicsSprite *sprite = new PhysicsSprite();
  135. sprite->initWithTexture(m_pSpriteTexture, CCRectMake(32 * idx,32 * idy,32,32));
  136. sprite->autorelease();
  137. parent->addChild(sprite);
  138. sprite->setPosition( CCPointMake( p.x, p.y) );
  139. //1.创建一个body定义结构体,用以指定body的初始属性,比如位置或者速度。
  140. b2BodyDef bodyDef;
  141. bodyDef.type = b2_dynamicBody;
  142. bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
  143. //2.调用world对象来创建一个body对象
  144. b2Body *body = world->CreateBody(&bodyDef);
  145. //3.为body对象定义一个shape,用以指定想要仿真的物体的几何形状。
  146. b2PolygonShape dynamicBox;
  147. dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box
  148. /*4.创建一个fixture定义,同时设置之前创建好的shape为fixture的一个属性,并且设置其它的属性,比如质量或者摩擦力。
  149. density,friction和restitution参数的意义:
  150. Density 就是单位体积的质量(密度)。因此,一个对象的密度越大,那么它就有更多的质量,当然就会越难以移动.
  151. Friction 就是摩擦力。它的范围是0-1.0, 0意味着没有摩擦,1代表最大摩擦,几乎移不动的摩擦。
  152. Restitution 回复力。它的范围也是0到1.0. 0意味着对象碰撞之后不会反弹,1意味着是完全弹性碰撞,会以同样的速度反弹。
  153. */
  154. b2FixtureDef fixtureDef;
  155. fixtureDef.shape = &dynamicBox;
  156. fixtureDef.density = 1.0f; //密度
  157. fixtureDef.friction = 0.3f; //摩擦力
  158. body->CreateFixture(&fixtureDef);
  159. //调用sprite的setPhysicsBody来为一个sprite设定body。
  160. sprite->setPhysicsBody(body);
  161. }
  162. //更新每个刚体相关联的精灵的位置和旋转信息
  163. void HelloWorld::update(float dt)
  164. {
  165. int velocityIterations = 8;
  166. int positionIterations = 1;
  167. /*
  168. Box2D的world是通过定期地调用Step方法来实现动画的。
  169. Step方法需要三个参数。
  170. 第一个是timeStep,它会告诉Box2D自从上次更新以后已经过去多长时间了,直接影响着刚体会在这一步移动多长距离。
  171. 不建议使用dt来作为timeStep的值,因为dt会上下浮动,刚体就不能以相同的速度移动了。
  172. 第二和第三个参数是迭代次数。它们被用于决定物理模拟的精确程度,也决定着计算刚体移动所需要的时间。
  173. */
  174. world->Step(0.015, velocityIterations, positionIterations);
  175. //在物理世界world中遍历每一个刚体body
  176. for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
  177. {
  178. if (b->GetUserData() != NULL) {
  179. //Synchronize the AtlasSprites position and rotation with the corresponding body
  180. CCSprite* myActor = (CCSprite*)b->GetUserData();
  181. myActor->setPosition( CCPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO) ); //单位转换 米->像素
  182. myActor->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) ); //单位转换 弧度->角度
  183. }
  184. }
  185. }
  186. void HelloWorld::ccTouchesEnded(CCSet* touches, CCEvent* event)
  187. {
  188. CCSetIterator it;
  189. CCTouch* touch;
  190. for( it = touches->begin(); it != touches->end(); it++)
  191. {
  192. touch = (CCTouch*)(*it);
  193. if(!touch) break;
  194. CCPoint location = touch->getLocation();
  195. addNewSpriteAtPosition( location );
  196. }
  197. }
  198. CCScene* HelloWorld::scene()
  199. {
  200. CCScene *scene = CCScene::create();
  201. CCLayer* layer = new HelloWorld();
  202. scene->addChild(layer);
  203. layer->release();
  204. return scene;
  205. }



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/652383
推荐阅读
相关标签
  

闽ICP备14008679号