CCPhysicsSprite.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /* Copyright (c) 2012 Scott Lembcke and Howling Moon Software
  2. * Copyright (c) 2012 cocos2d-x.org
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. #include "CCPhysicsSprite.h"
  23. #include "base/CCDirector.h"
  24. #include "base/CCEventDispatcher.h"
  25. #if (CC_ENABLE_CHIPMUNK_INTEGRATION || CC_ENABLE_BOX2D_INTEGRATION)
  26. #if (CC_ENABLE_CHIPMUNK_INTEGRATION && CC_ENABLE_BOX2D_INTEGRATION)
  27. #error "Either Chipmunk or Box2d should be enabled, but not both at the same time"
  28. #endif
  29. #if CC_ENABLE_CHIPMUNK_INTEGRATION
  30. #include "chipmunk/chipmunk.h"
  31. #elif CC_ENABLE_BOX2D_INTEGRATION
  32. #include "Box2D/Box2D.h"
  33. #endif
  34. NS_CC_EXT_BEGIN
  35. PhysicsSprite::PhysicsSprite()
  36. : _ignoreBodyRotation(false)
  37. , _CPBody(nullptr)
  38. , _pB2Body(nullptr)
  39. , _PTMRatio(0.0f)
  40. , _syncTransform(nullptr)
  41. {}
  42. PhysicsSprite* PhysicsSprite::create()
  43. {
  44. PhysicsSprite* pRet = new (std::nothrow) PhysicsSprite();
  45. if (pRet && pRet->init())
  46. {
  47. pRet->autorelease();
  48. }
  49. else
  50. {
  51. CC_SAFE_DELETE(pRet);
  52. }
  53. return pRet;
  54. }
  55. PhysicsSprite* PhysicsSprite::createWithTexture(Texture2D *pTexture)
  56. {
  57. PhysicsSprite* pRet = new (std::nothrow) PhysicsSprite();
  58. if (pRet && pRet->initWithTexture(pTexture))
  59. {
  60. pRet->autorelease();
  61. }
  62. else
  63. {
  64. CC_SAFE_DELETE(pRet);
  65. }
  66. return pRet;
  67. }
  68. PhysicsSprite* PhysicsSprite::createWithTexture(Texture2D *pTexture, const Rect& rect)
  69. {
  70. PhysicsSprite* pRet = new (std::nothrow) PhysicsSprite();
  71. if (pRet && pRet->initWithTexture(pTexture, rect))
  72. {
  73. pRet->autorelease();
  74. }
  75. else
  76. {
  77. CC_SAFE_DELETE(pRet);
  78. }
  79. return pRet;
  80. }
  81. PhysicsSprite* PhysicsSprite::createWithSpriteFrame(SpriteFrame *pSpriteFrame)
  82. {
  83. PhysicsSprite* pRet = new (std::nothrow) PhysicsSprite();
  84. if (pRet && pRet->initWithSpriteFrame(pSpriteFrame))
  85. {
  86. pRet->autorelease();
  87. }
  88. else
  89. {
  90. CC_SAFE_DELETE(pRet);
  91. }
  92. return pRet;
  93. }
  94. PhysicsSprite* PhysicsSprite::createWithSpriteFrameName(const char *pszSpriteFrameName)
  95. {
  96. PhysicsSprite* pRet = new (std::nothrow) PhysicsSprite();
  97. if (pRet && pRet->initWithSpriteFrameName(pszSpriteFrameName))
  98. {
  99. pRet->autorelease();
  100. }
  101. else
  102. {
  103. CC_SAFE_DELETE(pRet);
  104. }
  105. return pRet;
  106. }
  107. PhysicsSprite* PhysicsSprite::create(const char *pszFileName)
  108. {
  109. PhysicsSprite* pRet = new (std::nothrow) PhysicsSprite();
  110. if (pRet && pRet->initWithFile(pszFileName))
  111. {
  112. pRet->autorelease();
  113. }
  114. else
  115. {
  116. CC_SAFE_DELETE(pRet);
  117. }
  118. return pRet;
  119. }
  120. PhysicsSprite* PhysicsSprite::create(const char *pszFileName, const Rect& rect)
  121. {
  122. PhysicsSprite* pRet = new (std::nothrow) PhysicsSprite();
  123. if (pRet && pRet->initWithFile(pszFileName, rect))
  124. {
  125. pRet->autorelease();
  126. }
  127. else
  128. {
  129. CC_SAFE_DELETE(pRet);
  130. }
  131. return pRet;
  132. }
  133. // this method will only get called if the sprite is batched.
  134. // return YES if the physic's values (angles, position ) changed.
  135. // If you return NO, then getNodeToParentTransform won't be called.
  136. bool PhysicsSprite::isDirty() const
  137. {
  138. return true;
  139. }
  140. bool PhysicsSprite::isIgnoreBodyRotation() const
  141. {
  142. return _ignoreBodyRotation;
  143. }
  144. void PhysicsSprite::setIgnoreBodyRotation(bool bIgnoreBodyRotation)
  145. {
  146. _ignoreBodyRotation = bIgnoreBodyRotation;
  147. }
  148. // Override the setters and getters to always reflect the body's properties.
  149. const Vec2& PhysicsSprite::getPosition() const
  150. {
  151. return getPosFromPhysics();
  152. }
  153. void PhysicsSprite::getPosition(float* x, float* y) const
  154. {
  155. if (x == nullptr || y == nullptr) {
  156. return;
  157. }
  158. const Vec2& pos = getPosFromPhysics();
  159. *x = pos.x;
  160. *y = pos.y;
  161. }
  162. float PhysicsSprite::getPositionX() const
  163. {
  164. return getPosFromPhysics().x;
  165. }
  166. float PhysicsSprite::getPositionY() const
  167. {
  168. return getPosFromPhysics().y;
  169. }
  170. Vec3 PhysicsSprite::getPosition3D() const
  171. {
  172. Vec2 pos = getPosFromPhysics();
  173. return Vec3(pos.x, pos.y, 0);
  174. }
  175. //
  176. // Chipmunk only
  177. //
  178. cpBody* PhysicsSprite::getCPBody() const
  179. {
  180. #if CC_ENABLE_CHIPMUNK_INTEGRATION
  181. return _CPBody;
  182. #else
  183. CCASSERT(false, "Can't call chipmunk methods when Chipmunk is disabled");
  184. return nullptr;
  185. #endif
  186. }
  187. void PhysicsSprite::setCPBody(cpBody *pBody)
  188. {
  189. #if CC_ENABLE_CHIPMUNK_INTEGRATION
  190. _CPBody = pBody;
  191. #else
  192. CCASSERT(false, "Can't call chipmunk methods when Chipmunk is disabled");
  193. #endif
  194. }
  195. b2Body* PhysicsSprite::getB2Body() const
  196. {
  197. #if CC_ENABLE_BOX2D_INTEGRATION
  198. return _pB2Body;
  199. #else
  200. CCASSERT(false, "Can't call box2d methods when Box2d is disabled");
  201. return nullptr;
  202. #endif
  203. }
  204. void PhysicsSprite::setB2Body(b2Body *pBody)
  205. {
  206. #if CC_ENABLE_BOX2D_INTEGRATION
  207. _pB2Body = pBody;
  208. #else
  209. CC_UNUSED_PARAM(pBody);
  210. CCASSERT(false, "Can't call box2d methods when Box2d is disabled");
  211. #endif
  212. }
  213. float PhysicsSprite::getPTMRatio() const
  214. {
  215. #if CC_ENABLE_BOX2D_INTEGRATION
  216. return _PTMRatio;
  217. #else
  218. CCASSERT(false, "Can't call box2d methods when Box2d is disabled");
  219. return 0;
  220. #endif
  221. }
  222. void PhysicsSprite::setPTMRatio(float fRatio)
  223. {
  224. #if CC_ENABLE_BOX2D_INTEGRATION
  225. _PTMRatio = fRatio;
  226. #else
  227. CC_UNUSED_PARAM(fRatio);
  228. CCASSERT(false, "Can't call box2d methods when Box2d is disabled");
  229. #endif
  230. }
  231. //
  232. // Common to Box2d and Chipmunk
  233. //
  234. const Vec2& PhysicsSprite::getPosFromPhysics() const
  235. {
  236. static Vec2 s_physicPosion;
  237. #if CC_ENABLE_CHIPMUNK_INTEGRATION
  238. cpVect cpPos = cpBodyGetPosition(_CPBody);
  239. s_physicPosion = Vec2(cpPos.x, cpPos.y);
  240. #elif CC_ENABLE_BOX2D_INTEGRATION
  241. b2Vec2 pos = _pB2Body->GetPosition();
  242. float x = pos.x * _PTMRatio;
  243. float y = pos.y * _PTMRatio;
  244. s_physicPosion.set(x,y);
  245. #endif
  246. return s_physicPosion;
  247. }
  248. void PhysicsSprite::setPosition(float x, float y)
  249. {
  250. #if CC_ENABLE_CHIPMUNK_INTEGRATION
  251. cpVect cpPos = cpv(x, y);
  252. cpBodySetPosition(_CPBody, cpPos);
  253. #elif CC_ENABLE_BOX2D_INTEGRATION
  254. float angle = _pB2Body->GetAngle();
  255. _pB2Body->SetTransform(b2Vec2(x / _PTMRatio, y / _PTMRatio), angle);
  256. #endif
  257. }
  258. void PhysicsSprite::setPosition(const Vec2 &pos)
  259. {
  260. setPosition(pos.x, pos.y);
  261. }
  262. void PhysicsSprite::setPositionX(float x)
  263. {
  264. setPosition(x, getPositionY());
  265. }
  266. void PhysicsSprite::setPositionY(float y)
  267. {
  268. setPosition(getPositionX(), y);
  269. }
  270. void PhysicsSprite::setPosition3D(const Vec3& position)
  271. {
  272. setPosition(position.x, position.y);
  273. }
  274. float PhysicsSprite::getRotation() const
  275. {
  276. #if CC_ENABLE_CHIPMUNK_INTEGRATION
  277. return (_ignoreBodyRotation ? Sprite::getRotation() : -CC_RADIANS_TO_DEGREES(cpBodyGetAngle(_CPBody)));
  278. #elif CC_ENABLE_BOX2D_INTEGRATION
  279. return (_ignoreBodyRotation ? Sprite::getRotation() :
  280. CC_RADIANS_TO_DEGREES(_pB2Body->GetAngle()));
  281. #else
  282. return 0.0f;
  283. #endif
  284. }
  285. void PhysicsSprite::setRotation(float fRotation)
  286. {
  287. if (_ignoreBodyRotation)
  288. {
  289. Sprite::setRotation(fRotation);
  290. }
  291. #if CC_ENABLE_CHIPMUNK_INTEGRATION
  292. else
  293. {
  294. cpBodySetAngle(_CPBody, -CC_DEGREES_TO_RADIANS(fRotation));
  295. }
  296. #elif CC_ENABLE_BOX2D_INTEGRATION
  297. else
  298. {
  299. b2Vec2 p = _pB2Body->GetPosition();
  300. float radians = CC_DEGREES_TO_RADIANS(fRotation);
  301. _pB2Body->SetTransform(p, radians);
  302. }
  303. #endif
  304. }
  305. void PhysicsSprite::syncPhysicsTransform() const
  306. {
  307. // Although scale is not used by physics engines, it is calculated just in case
  308. // the sprite is animated (scaled up/down) using actions.
  309. // For more info see: http://www.cocos2d-iphone.org/forum/topic/68990
  310. #if CC_ENABLE_CHIPMUNK_INTEGRATION
  311. cpVect rot = (_ignoreBodyRotation ? cpvforangle(-CC_DEGREES_TO_RADIANS(_rotationX)) : cpBodyGetRotation(_CPBody));
  312. float x = cpBodyGetPosition(_CPBody).x + rot.x * -_anchorPointInPoints.x * _scaleX - rot.y * -_anchorPointInPoints.y * _scaleY;
  313. float y = cpBodyGetPosition(_CPBody).y + rot.y * -_anchorPointInPoints.x * _scaleX + rot.x * -_anchorPointInPoints.y * _scaleY;
  314. if (_ignoreAnchorPointForPosition)
  315. {
  316. x += _anchorPointInPoints.x;
  317. y += _anchorPointInPoints.y;
  318. }
  319. float mat[] = { (float)rot.x * _scaleX, (float)rot.y * _scaleX, 0, 0,
  320. (float)-rot.y * _scaleY, (float)rot.x * _scaleY, 0, 0,
  321. 0, 0, 1, 0,
  322. x, y, 0, 1};
  323. _transform.set(mat);
  324. #elif CC_ENABLE_BOX2D_INTEGRATION
  325. b2Vec2 pos = _pB2Body->GetPosition();
  326. float x = pos.x * _PTMRatio;
  327. float y = pos.y * _PTMRatio;
  328. if (_ignoreAnchorPointForPosition)
  329. {
  330. x += _anchorPointInPoints.x;
  331. y += _anchorPointInPoints.y;
  332. }
  333. // Make matrix
  334. float radians = _pB2Body->GetAngle();
  335. float c = cosf(radians);
  336. float s = sinf(radians);
  337. if (!_anchorPointInPoints.isZero())
  338. {
  339. x += ((c * -_anchorPointInPoints.x * _scaleX) + (-s * -_anchorPointInPoints.y * _scaleY));
  340. y += ((s * -_anchorPointInPoints.x * _scaleX) + (c * -_anchorPointInPoints.y * _scaleY));
  341. }
  342. // Rot, Translate Matrix
  343. float mat[] = { (float)c * _scaleX, (float)s * _scaleX, 0, 0,
  344. (float)-s * _scaleY, (float)c * _scaleY, 0, 0,
  345. 0, 0, 1, 0,
  346. x, y, 0, 1};
  347. _transform.set(mat);
  348. #endif
  349. }
  350. void PhysicsSprite::onEnter()
  351. {
  352. Node::onEnter();
  353. _syncTransform = Director::getInstance()->getEventDispatcher()->addCustomEventListener(Director::EVENT_AFTER_UPDATE, std::bind(&PhysicsSprite::afterUpdate, this, std::placeholders::_1));
  354. _syncTransform->retain();
  355. }
  356. void PhysicsSprite::onExit()
  357. {
  358. if (_syncTransform != nullptr)
  359. {
  360. Director::getInstance()->getEventDispatcher()->removeEventListener(_syncTransform);
  361. _syncTransform->release();
  362. }
  363. Node::onExit();
  364. }
  365. void PhysicsSprite::afterUpdate(EventCustom* /*event*/)
  366. {
  367. syncPhysicsTransform();
  368. _transformDirty = false;
  369. _transformUpdated = true;
  370. setDirtyRecursively(true);
  371. }
  372. NS_CC_EXT_END
  373. #endif // CC_ENABLE_CHIPMUNK_INTEGRATION || CC_ENABLE_BOX2D_INTEGRATION