box2dbody.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * Box2D QML plugin
  3. * Copyright (C) 2010 Nokia Corporation
  4. *
  5. * This file is part of the Box2D QML plugin.
  6. *
  7. * This library is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation; either version 2.1 of the License, or (at
  10. * your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  14. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  15. * License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this library; If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "box2dbody.h"
  21. #include "box2dfixture.h"
  22. #include "box2dworld.h"
  23. #include <cmath>
  24. Box2DBody::Box2DBody(QDeclarativeItem *parent) :
  25. QDeclarativeItem(parent),
  26. mBody(0),
  27. mWorld(0),
  28. mLinearDamping(0.0f),
  29. mAngularDamping(0.0f),
  30. mBodyType(Dynamic),
  31. mBullet(false),
  32. mSleepingAllowed(true),
  33. mFixedRotation(false),
  34. mActive(true),
  35. mSynchronizing(false),
  36. mInitializePending(false)
  37. {
  38. setTransformOrigin(TopLeft);
  39. connect(this, SIGNAL(rotationChanged()), SLOT(onRotationChanged()));
  40. }
  41. Box2DBody::~Box2DBody()
  42. {
  43. }
  44. void Box2DBody::setLinearDamping(qreal linearDamping)
  45. {
  46. if (mLinearDamping == linearDamping)
  47. return;
  48. mLinearDamping = linearDamping;
  49. if (mBody)
  50. mBody->SetLinearDamping(linearDamping);
  51. emit linearDampingChanged();
  52. }
  53. void Box2DBody::setAngularDamping(qreal angularDamping)
  54. {
  55. if (mAngularDamping == angularDamping)
  56. return;
  57. mAngularDamping = angularDamping;
  58. if (mBody)
  59. mBody->SetAngularDamping(angularDamping);
  60. emit angularDampingChanged();
  61. }
  62. void Box2DBody::setBodyType(BodyType bodyType)
  63. {
  64. if (mBodyType == bodyType)
  65. return;
  66. mBodyType = bodyType;
  67. if (mBody)
  68. mBody->SetType(static_cast<b2BodyType>(bodyType));
  69. emit bodyTypeChanged();
  70. }
  71. void Box2DBody::setBullet(bool bullet)
  72. {
  73. if (mBullet == bullet)
  74. return;
  75. mBullet = bullet;
  76. if (mBody)
  77. mBody->SetBullet(bullet);
  78. emit bulletChanged();
  79. }
  80. void Box2DBody::setSleepingAllowed(bool allowed)
  81. {
  82. if (mSleepingAllowed == allowed)
  83. return;
  84. mSleepingAllowed = allowed;
  85. if (mBody)
  86. mBody->SetSleepingAllowed(allowed);
  87. emit sleepingAllowedChanged();
  88. }
  89. void Box2DBody::setFixedRotation(bool fixedRotation)
  90. {
  91. if (mFixedRotation == fixedRotation)
  92. return;
  93. mFixedRotation = fixedRotation;
  94. if (mBody)
  95. mBody->SetFixedRotation(fixedRotation);
  96. emit fixedRotationChanged();
  97. }
  98. void Box2DBody::setActive(bool active)
  99. {
  100. if (mActive == active)
  101. return;
  102. mActive = active;
  103. if (mBody)
  104. mBody->SetActive(active);
  105. }
  106. void Box2DBody::setLinearVelocity(const QPointF &linearVelocity)
  107. {
  108. if (mLinearVelocity == linearVelocity)
  109. return;
  110. mLinearVelocity = linearVelocity;
  111. if (mBody)
  112. mBody->SetLinearVelocity(b2Vec2(mLinearVelocity.x() / scaleRatio,
  113. -mLinearVelocity.y() / scaleRatio));
  114. emit linearVelocityChanged();
  115. }
  116. void Box2DBody::setAngularVelocity(float angularVelocity)
  117. {
  118. if (mAngularVelocity == angularVelocity)
  119. return;
  120. mAngularVelocity = angularVelocity;
  121. if (mBody)
  122. mBody->SetAngularVelocity(angularVelocity);
  123. emit angularVelocityChanged();
  124. }
  125. QDeclarativeListProperty<Box2DFixture> Box2DBody::fixtures()
  126. {
  127. return QDeclarativeListProperty<Box2DFixture>(this, 0,
  128. &Box2DBody::append_fixture);
  129. }
  130. void Box2DBody::append_fixture(QDeclarativeListProperty<Box2DFixture> *list,
  131. Box2DFixture *fixture)
  132. {
  133. Box2DBody *body = static_cast<Box2DBody*>(list->object);
  134. fixture->setParentItem(body);
  135. body->mFixtures.append(fixture);
  136. }
  137. void Box2DBody::initialize(b2World *world)
  138. {
  139. mWorld = world;
  140. if (!isComponentComplete()) {
  141. // When components are created dynamically, they get their parent
  142. // assigned before they have been completely initialized. In that case
  143. // we need to delay initialization.
  144. mInitializePending = true;
  145. return;
  146. }
  147. b2BodyDef bodyDef;
  148. bodyDef.type = static_cast<b2BodyType>(mBodyType);
  149. bodyDef.position.Set(x() / scaleRatio, -y() / scaleRatio);
  150. bodyDef.angle = -(rotation() * (2 * M_PI)) / 360.0;
  151. bodyDef.linearDamping = mLinearDamping;
  152. bodyDef.angularDamping = mAngularDamping;
  153. bodyDef.bullet = mBullet;
  154. bodyDef.allowSleep = mSleepingAllowed;
  155. bodyDef.fixedRotation = mFixedRotation;
  156. mBody = world->CreateBody(&bodyDef);
  157. mInitializePending = false;
  158. foreach (Box2DFixture *fixture, mFixtures)
  159. fixture->createFixture(mBody);
  160. emit bodyCreated();
  161. }
  162. /**
  163. * Synchronizes the state of this body with the internal Box2D state.
  164. */
  165. void Box2DBody::synchronize()
  166. {
  167. Q_ASSERT(mBody);
  168. mSynchronizing = true;
  169. const b2Vec2 position = mBody->GetPosition();
  170. const float32 angle = mBody->GetAngle();
  171. const qreal newX = position.x * scaleRatio;
  172. const qreal newY = -position.y * scaleRatio;
  173. const qreal newRotation = -(angle * 360.0) / (2 * M_PI);
  174. // Do fuzzy comparisions to avoid small inaccuracies causing repaints
  175. if (!qFuzzyCompare(x(), newX) || !qFuzzyCompare(y(), newY))
  176. setPos(newX, newY);
  177. if (!qFuzzyCompare(rotation(), newRotation))
  178. setRotation(newRotation);
  179. b2Vec2 linearVelocity = mBody->GetLinearVelocity();
  180. setLinearVelocity(QPointF(linearVelocity.x * scaleRatio,
  181. -linearVelocity.y * scaleRatio));
  182. float angularVelocity = mBody->GetAngularVelocity();
  183. setAngularVelocity(angularVelocity);
  184. mSynchronizing = false;
  185. }
  186. void Box2DBody::resetVelocities()
  187. {
  188. mBody->SetLinearVelocity(b2Vec2(0, 0));
  189. mBody->SetAngularVelocity(0);
  190. }
  191. void Box2DBody::cleanup(b2World *world)
  192. {
  193. world->DestroyBody(mBody);
  194. mBody = 0;
  195. mWorld = 0;
  196. }
  197. void Box2DBody::componentComplete()
  198. {
  199. QDeclarativeItem::componentComplete();
  200. if (mInitializePending)
  201. initialize(mWorld);
  202. }
  203. b2Body* Box2DBody::body() const
  204. {
  205. return mBody;
  206. }
  207. void Box2DBody::geometryChanged(const QRectF &newGeometry,
  208. const QRectF &oldGeometry)
  209. {
  210. if (!mSynchronizing && mBody) {
  211. if (newGeometry.topLeft() != oldGeometry.topLeft()) {
  212. const QPointF pos = newGeometry.topLeft();
  213. mBody->SetTransform(b2Vec2(pos.x() / scaleRatio,
  214. -pos.y() / scaleRatio),
  215. mBody->GetAngle());
  216. }
  217. }
  218. QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
  219. }
  220. void Box2DBody::onRotationChanged()
  221. {
  222. if (!mSynchronizing && mBody) {
  223. mBody->SetTransform(mBody->GetPosition(),
  224. (rotation() * 2 * M_PI) / -360.0);
  225. }
  226. }
  227. void Box2DBody::applyLinearImpulse(const QPointF &impulse,
  228. const QPointF &point)
  229. {
  230. if (mBody) {
  231. mBody->ApplyLinearImpulse(b2Vec2(impulse.x() / scaleRatio,
  232. -impulse.y() / scaleRatio),
  233. b2Vec2(point.x() / scaleRatio,
  234. -point.y() / scaleRatio));
  235. }
  236. }
  237. void Box2DBody::applyTorque(qreal torque)
  238. {
  239. if (mBody)
  240. mBody->ApplyTorque(torque);
  241. }
  242. QPointF Box2DBody::getWorldCenter() const
  243. {
  244. QPointF worldCenter;
  245. if (mBody) {
  246. const b2Vec2 &center = mBody->GetWorldCenter();
  247. worldCenter.setX(center.x * scaleRatio);
  248. worldCenter.setY(-center.y * scaleRatio);
  249. }
  250. return worldCenter;
  251. }