/FlappyBird.spritebuilder/Source/libs/cocos2d-iphone.backup/UnitTests/CCPhysicsTests.m

https://gitlab.com/lirao/FlappyBird-SpriteBuilder · Objective C · 1110 lines · 767 code · 262 blank · 81 comment · 46 complexity · c061fda80d9133db252fb09c65752e0a MD5 · raw file

  1. //
  2. // CCPhysicsTests.m
  3. // CCPhysicsTests
  4. //
  5. // Created by Scott Lembcke on 10/11/13.
  6. //
  7. //
  8. #import <XCTest/XCTest.h>
  9. #import "cocos2d.h"
  10. #import "CCPhysics+ObjectiveChipmunk.h"
  11. #import "CCDirector_Private.h"
  12. @interface CCScheduler(Test)
  13. -(CCTimer*)fixedUpdateTimer;
  14. @end
  15. @interface CCPhysicsTests : XCTestCase <CCPhysicsCollisionDelegate>
  16. @end
  17. @implementation CCPhysicsTests
  18. static void
  19. TestBasicSequenceHelper(id self, CCPhysicsNode *physicsNode, CCNode *parent, CCNode *node, CCPhysicsBody *body)
  20. {
  21. // Probably not necessary, but doesn't hurt.
  22. CCScene *scene = [CCScene node];
  23. [scene addChild:physicsNode];
  24. // Allow the parent to be the physics node.
  25. if(parent != physicsNode) [physicsNode addChild:parent];
  26. CGPoint position = node.position;
  27. float rotation = node.rotation;
  28. const float accuracy = 1e-4;
  29. // Sanity check.
  30. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  31. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  32. // Check that setting the position works in this state.
  33. node.position = position;
  34. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  35. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  36. [parent addChild:node];
  37. // Check that setting the position works in this state.
  38. node.position = position;
  39. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  40. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  41. // Set the physics body.
  42. // Node's internal transform is still used since the onEnter hasn't happened.
  43. node.physicsBody = body;
  44. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  45. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  46. // Check that setting the position works in this state.
  47. node.position = position;
  48. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  49. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  50. // Force on onEnter to be called.
  51. // Body's transform is now used instead of the node's.
  52. [scene onEnter];
  53. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  54. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  55. // Check that setting the position works in this state.
  56. node.position = position;
  57. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  58. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  59. // Remove the node and check the position is still correct
  60. [node removeFromParent];
  61. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  62. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  63. // Check that setting the position works in this state.
  64. node.position = position;
  65. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  66. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  67. // Add back to the physics
  68. [parent addChild:node];
  69. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  70. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  71. // Check that setting the position works in this state.
  72. node.position = position;
  73. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  74. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  75. // Force onExit
  76. [scene onExit];
  77. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  78. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  79. // Check that setting the position works in this state.
  80. node.position = position;
  81. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  82. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  83. // Force re-entry to the scene.
  84. [scene onEnter];
  85. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  86. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  87. // Check that setting the position works in this state.
  88. node.position = position;
  89. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  90. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  91. // Try switching the physics body.
  92. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:ccp(1,1)];
  93. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  94. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  95. // Check that setting the position works in this state.
  96. node.position = position;
  97. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  98. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  99. // Test setting the body to nil.
  100. node.physicsBody = nil;
  101. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  102. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  103. // Check that setting the position works in this state.
  104. node.position = position;
  105. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  106. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  107. // Set back to the original body
  108. node.physicsBody = body;
  109. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  110. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  111. // Check that setting the position works in this state.
  112. node.position = position;
  113. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  114. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  115. // Try setting the body when not added to a scene anymore.
  116. [node removeFromParent];
  117. node.physicsBody = nil;
  118. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  119. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  120. // Check that setting the position works in this state.
  121. node.position = position;
  122. XCTAssertTrue(ccpDistance(node.position, position) < accuracy, @"");
  123. XCTAssertEqualWithAccuracy(node.rotation, rotation, accuracy, @"");
  124. // Terrible things happen when you don't call this due to Cocos2D global variables.
  125. [scene onExit];
  126. }
  127. -(void)testBasicSequences1
  128. {
  129. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  130. CCNode *node = [CCNode node];
  131. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  132. TestBasicSequenceHelper(self, physicsNode, physicsNode, node, body);
  133. }
  134. -(void)testBasicSequences2
  135. {
  136. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  137. CCNode *node = [CCNode node];
  138. node.position = ccp(100, 100);
  139. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  140. TestBasicSequenceHelper(self, physicsNode, physicsNode, node, body);
  141. }
  142. -(void)testBasicSequences3
  143. {
  144. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  145. CCNode *node = [CCNode node];
  146. node.contentSize = CGSizeMake(30, 30);
  147. node.anchorPoint = ccp(0.5, 0.5);
  148. node.position = ccp(100, 100);
  149. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  150. TestBasicSequenceHelper(self, physicsNode, physicsNode, node, body);
  151. }
  152. -(void)testBasicSequences4
  153. {
  154. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  155. CCNode *node = [CCNode node];
  156. node.contentSize = CGSizeMake(30, 30);
  157. node.anchorPoint = ccp(0.5, 0.5);
  158. node.position = ccp(100, 100);
  159. node.rotation = 30;
  160. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  161. TestBasicSequenceHelper(self, physicsNode, physicsNode, node, body);
  162. }
  163. -(void)testBasicSequences5
  164. {
  165. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  166. CCNode *node = [CCNode node];
  167. node.contentSize = CGSizeMake(30, 30);
  168. node.anchorPoint = ccp(0.5, 0.5);
  169. node.position = ccp(100, 100);
  170. node.rotation = 30;
  171. node.scaleX = 2.0;
  172. node.scaleY = 3.0;
  173. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  174. TestBasicSequenceHelper(self, physicsNode, physicsNode, node, body);
  175. }
  176. -(void)testBasicSequences6
  177. {
  178. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  179. CCNode *parent = [CCNode node];
  180. CCNode *node = [CCNode node];
  181. node.contentSize = CGSizeMake(30, 30);
  182. node.anchorPoint = ccp(0.5, 0.5);
  183. node.position = ccp(100, 100);
  184. node.rotation = 30;
  185. node.scaleX = 2.0;
  186. node.scaleY = 3.0;
  187. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  188. TestBasicSequenceHelper(self, physicsNode, parent, node, body);
  189. }
  190. -(void)testBasicSequences7
  191. {
  192. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  193. CCNode *parent = [CCNode node];
  194. parent.position = ccp(20, 60);
  195. CCNode *node = [CCNode node];
  196. node.contentSize = CGSizeMake(30, 30);
  197. node.anchorPoint = ccp(0.5, 0.5);
  198. node.position = ccp(100, 100);
  199. node.rotation = 30;
  200. node.scaleX = 2.0;
  201. node.scaleY = 3.0;
  202. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  203. TestBasicSequenceHelper(self, physicsNode, parent, node, body);
  204. }
  205. -(void)testBasicSequences8
  206. {
  207. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  208. CCNode *parent = [CCNode node];
  209. parent.contentSize = CGSizeMake(25, 35);
  210. parent.anchorPoint = ccp(0.3, 0.7);
  211. parent.position = ccp(20, 60);
  212. CCNode *node = [CCNode node];
  213. node.contentSize = CGSizeMake(30, 30);
  214. node.anchorPoint = ccp(0.5, 0.5);
  215. node.position = ccp(100, 100);
  216. node.rotation = 30;
  217. node.scaleX = 2.0;
  218. node.scaleY = 3.0;
  219. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  220. TestBasicSequenceHelper(self, physicsNode, parent, node, body);
  221. }
  222. -(void)testBasicSequences9
  223. {
  224. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  225. CCNode *parent = [CCNode node];
  226. parent.contentSize = CGSizeMake(25, 35);
  227. parent.anchorPoint = ccp(0.3, 0.7);
  228. parent.position = ccp(20, 60);
  229. parent.rotation = -10;
  230. CCNode *node = [CCNode node];
  231. node.contentSize = CGSizeMake(30, 30);
  232. node.anchorPoint = ccp(0.5, 0.5);
  233. node.position = ccp(100, 100);
  234. node.rotation = 35;
  235. node.scaleX = 2.0;
  236. node.scaleY = 3.0;
  237. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  238. TestBasicSequenceHelper(self, physicsNode, parent, node, body);
  239. }
  240. -(void)testBasicSequences10
  241. {
  242. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  243. CCNode *parent = [CCNode node];
  244. parent.contentSize = CGSizeMake(25, 35);
  245. parent.anchorPoint = ccp(0.3, 0.7);
  246. parent.position = ccp(20, 60);
  247. parent.rotation = -15;
  248. parent.scaleX = 1.5;
  249. parent.scaleY = 8.0;
  250. CCNode *node = [CCNode node];
  251. node.contentSize = CGSizeMake(30, 30);
  252. node.anchorPoint = ccp(0,0);
  253. node.position = ccp(100, 100);
  254. node.rotation = 30;
  255. node.scaleX = 2.0;
  256. node.scaleY = 3.0;
  257. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  258. TestBasicSequenceHelper(self, physicsNode, parent, node, body);
  259. }
  260. -(void)testBasicSequences11
  261. {
  262. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  263. CCNode *parent = [CCNode node];
  264. parent.contentSize = CGSizeMake(25, 35);
  265. parent.anchorPoint = ccp(0.3, 0.7);
  266. parent.position = ccp(20, 60);
  267. parent.rotation = -15;
  268. parent.scaleX = 1.5;
  269. parent.scaleY = 8.0;
  270. CCNode *node = [CCNode node];
  271. node.contentSize = CGSizeMake(30, 30);
  272. node.anchorPoint = ccp(0,0);
  273. node.position = ccp(100, 100);
  274. node.rotation = 30;
  275. node.scaleX = 2.0;
  276. node.scaleY = 3.0;
  277. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  278. body.type = CCPhysicsBodyTypeStatic;
  279. TestBasicSequenceHelper(self, physicsNode, parent, node, body);
  280. }
  281. -(void)testDynamicAnchorPoint
  282. {
  283. cpFloat accuracy = 1e-4;
  284. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  285. CCNode *node = [CCNode node];
  286. node.contentSize = CGSizeMake(2, 2);
  287. node.anchorPoint = ccp(0.5, 0.5);
  288. XCTAssert(ccpDistance(node.position, CGPointZero) < accuracy, @"");
  289. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  290. node.physicsBody.type = CCPhysicsBodyTypeDynamic;
  291. XCTAssert(ccpDistance(node.position, CGPointZero) < accuracy, @"");
  292. [physicsNode addChild:node];
  293. [physicsNode onEnter];
  294. XCTAssert(ccpDistance(node.position, CGPointZero) < accuracy, @"");
  295. node.rotation = 90;
  296. XCTAssert(ccpDistance(node.position, CGPointZero) < accuracy, @"");
  297. [physicsNode onExit];
  298. }
  299. -(void)testStaticAnchorPoint
  300. {
  301. cpFloat accuracy = 1e-4;
  302. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  303. CCNode *node = [CCNode node];
  304. node.contentSize = CGSizeMake(2, 2);
  305. node.anchorPoint = ccp(0.5, 0.5);
  306. XCTAssert(ccpDistance(node.position, CGPointZero) < accuracy, @"");
  307. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  308. node.physicsBody.type = CCPhysicsBodyTypeStatic;
  309. XCTAssert(ccpDistance(node.position, CGPointZero) < accuracy, @"");
  310. [physicsNode addChild:node];
  311. [physicsNode onEnter];
  312. XCTAssert(ccpDistance(node.position, CGPointZero) < accuracy, @"");
  313. node.rotation = 90;
  314. XCTAssert(ccpDistance(node.position, CGPointZero) < accuracy, @"");
  315. [physicsNode onExit];
  316. }
  317. -(void)testCollisionGroups
  318. {
  319. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  320. NSString *noCollide = @"nocollide";
  321. CCNode *node1 = [CCNode node];
  322. node1.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  323. node1.physicsBody.collisionGroup = noCollide;
  324. [physicsNode addChild:node1];
  325. CCNode *node2 = [CCNode node];
  326. node2.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  327. node2.physicsBody.collisionGroup = noCollide;
  328. [physicsNode addChild:node2];
  329. // Force entering the scene to set up the physics objects.
  330. [physicsNode onEnter];
  331. // Step the physics for a while.
  332. for(int i=0; i<100; i++){
  333. [physicsNode fixedUpdate:1.0/60.0];
  334. }
  335. // Both nodes should be at (0, 0)
  336. XCTAssertTrue(CGPointEqualToPoint(node1.position, CGPointZero) , @"");
  337. XCTAssertTrue(CGPointEqualToPoint(node2.position, CGPointZero) , @"");
  338. [physicsNode onExit];
  339. }
  340. -(void)testAffectedByGravity
  341. {
  342. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  343. physicsNode.gravity = ccp(0, -100);
  344. NSString *noCollide = @"nocollide";
  345. CCNode *node1 = [CCNode node];
  346. node1.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  347. node1.physicsBody.collisionGroup = noCollide;
  348. [physicsNode addChild:node1];
  349. CCNode *node2 = [CCNode node];
  350. node2.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  351. node2.physicsBody.collisionGroup = noCollide;
  352. node2.physicsBody.affectedByGravity = NO;
  353. [physicsNode addChild:node2];
  354. // Force entering the scene to set up the physics objects.
  355. [physicsNode onEnter];
  356. // Step the physics for a while.
  357. for(int i=0; i<100; i++){
  358. [physicsNode fixedUpdate:1.0/60.0];
  359. }
  360. // Node1 should move down due to gravity
  361. XCTAssertTrue(node1.position.y < 0.0, @"");
  362. // Node2 should stay at (0, 0)
  363. XCTAssertTrue(node2.position.y == 0.0, @"");
  364. [physicsNode onExit];
  365. }
  366. -(void)testAllowsRotation
  367. {
  368. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  369. [physicsNode onEnter];
  370. {
  371. // Regular body.
  372. CCNode *node = [CCNode node];
  373. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  374. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  375. [physicsNode addChild:node];
  376. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  377. XCTAssert(node.physicsBody.body.moment < INFINITY, @"");
  378. }{
  379. // Set before adding.
  380. CCNode *node = [CCNode node];
  381. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  382. node.physicsBody.allowsRotation = NO;
  383. XCTAssert(node.physicsBody.allowsRotation == NO, @"");
  384. [physicsNode addChild:node];
  385. XCTAssert(node.physicsBody.allowsRotation == NO, @"");
  386. XCTAssert(node.physicsBody.body.moment == INFINITY, @"");
  387. }{
  388. // Set after adding.
  389. CCNode *node = [CCNode node];
  390. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  391. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  392. [physicsNode addChild:node];
  393. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  394. node.physicsBody.allowsRotation = NO;
  395. XCTAssert(node.physicsBody.allowsRotation == NO, @"");
  396. XCTAssert(node.physicsBody.body.moment == INFINITY, @"");
  397. }{
  398. // Set and reverted before adding.
  399. CCNode *node = [CCNode node];
  400. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  401. node.physicsBody.allowsRotation = NO;
  402. XCTAssert(node.physicsBody.allowsRotation == NO, @"");
  403. node.physicsBody.allowsRotation = YES;
  404. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  405. [physicsNode addChild:node];
  406. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  407. XCTAssert(node.physicsBody.body.moment < INFINITY, @"");
  408. }{
  409. // Set before and reverted after adding.
  410. CCNode *node = [CCNode node];
  411. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  412. node.physicsBody.allowsRotation = NO;
  413. XCTAssert(node.physicsBody.allowsRotation == NO, @"");
  414. [physicsNode addChild:node];
  415. XCTAssert(node.physicsBody.allowsRotation == NO, @"");
  416. node.physicsBody.allowsRotation = YES;
  417. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  418. XCTAssert(node.physicsBody.body.moment < INFINITY, @"");
  419. }{
  420. // Set reverted after adding.
  421. CCNode *node = [CCNode node];
  422. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  423. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  424. [physicsNode addChild:node];
  425. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  426. node.physicsBody.allowsRotation = NO;
  427. XCTAssert(node.physicsBody.allowsRotation == NO, @"");
  428. node.physicsBody.allowsRotation = YES;
  429. XCTAssert(node.physicsBody.allowsRotation == YES, @"");
  430. XCTAssert(node.physicsBody.body.moment < INFINITY, @"");
  431. }
  432. [physicsNode onExit];
  433. }
  434. -(void)testBodyType
  435. {
  436. CGPoint points[3] = {};
  437. // Regular bodies should default to being dynamic.
  438. XCTAssertEqual([CCPhysicsBody bodyWithCircleOfRadius:0 andCenter:CGPointZero].type, CCPhysicsBodyTypeDynamic, @"");
  439. XCTAssertEqual([CCPhysicsBody bodyWithPillFrom:ccp(0, 1) to:ccp(1, 0) cornerRadius:0].type, CCPhysicsBodyTypeDynamic, @"");
  440. XCTAssertEqual([CCPhysicsBody bodyWithPolygonFromPoints:points count:3 cornerRadius:0].type, CCPhysicsBodyTypeDynamic, @"");
  441. XCTAssertEqual([CCPhysicsBody bodyWithRect:CGRectZero cornerRadius:0].type, CCPhysicsBodyTypeDynamic, @"");
  442. // Polyline bodies should default to being static bodies.
  443. XCTAssertEqual([CCPhysicsBody bodyWithPolylineFromRect:CGRectZero cornerRadius:0].type, CCPhysicsBodyTypeStatic, @"");
  444. XCTAssertEqual([CCPhysicsBody bodyWithPolylineFromPoints:points count:3 cornerRadius:0 looped:YES].type, CCPhysicsBodyTypeStatic, @"");
  445. // Test body type setters
  446. CCPhysicsBody *body = [CCPhysicsBody bodyWithCircleOfRadius:0 andCenter:CGPointZero];
  447. body.type = CCPhysicsBodyTypeStatic;
  448. XCTAssertEqual(body.type, CCPhysicsBodyTypeStatic, @"");
  449. XCTAssertEqual(body.body.type, CP_BODY_TYPE_STATIC, @"");
  450. // body.type = CCPhysicsBodyTypeKinematic;
  451. // XCTAssertEqual(body.type, CCPhysicsBodyTypeKinematic, @"");
  452. // XCTAssertEqual(body.body.type, CP_BODY_TYPE_KINEMATIC, @"");
  453. body.type = CCPhysicsBodyTypeDynamic;
  454. XCTAssertEqual(body.type, CCPhysicsBodyTypeDynamic, @"");
  455. XCTAssertEqual(body.body.type, CP_BODY_TYPE_DYNAMIC, @"");
  456. }
  457. -(void)testBreakingJoints
  458. {
  459. CCPhysicsNode *physics = [CCPhysicsNode node];
  460. physics.gravity = ccp(0, -100);
  461. CGRect rect = CGRectMake(0, 0, 50, 50);
  462. CCPhysicsJoint *joint1, *joint2, *joint3, *joint4;
  463. // These should break.
  464. {
  465. CCNode *node1 = [CCNode node];
  466. node1.position = ccp(100, 200);
  467. CCPhysicsBody *body1 = node1.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
  468. body1.type = CCPhysicsBodyTypeStatic;
  469. [physics addChild:node1];
  470. CCNode *node2 = [CCNode node];
  471. node2.position = ccp(100, 100);
  472. CCPhysicsBody *body2 = node2.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
  473. [physics addChild:node2];
  474. joint1 = [CCPhysicsJoint connectedPivotJointWithBodyA:body1 bodyB:body2 anchorA:ccp(rect.size.width/2.0, -rect.size.height/4.0)];
  475. joint1.breakingForce = -physics.gravity.y*body2.mass*0.9;
  476. }{
  477. CCNode *node1 = [CCNode node];
  478. node1.position = ccp(200, 200);
  479. CCPhysicsBody *body1 = node1.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
  480. body1.type = CCPhysicsBodyTypeStatic;
  481. [physics addChild:node1];
  482. CCNode *node2 = [CCNode node];
  483. node2.position = ccp(200, 100);
  484. CCPhysicsBody *body2 = node2.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
  485. [physics addChild:node2];
  486. joint2 = [CCPhysicsJoint connectedDistanceJointWithBodyA:body1 bodyB:body2 anchorA:ccp(rect.size.width/2.0, 0.0) anchorB:ccp(rect.size.width/2.0, rect.size.height)];
  487. joint2.breakingForce = -physics.gravity.y*body2.mass*0.9;
  488. }
  489. // These shouldn't
  490. {
  491. CCNode *node1 = [CCNode node];
  492. node1.position = ccp(300, 200);
  493. CCPhysicsBody *body1 = node1.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
  494. body1.type = CCPhysicsBodyTypeStatic;
  495. [physics addChild:node1];
  496. CCNode *node2 = [CCNode node];
  497. node2.position = ccp(300, 100);
  498. CCPhysicsBody *body2 = node2.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
  499. [physics addChild:node2];
  500. joint3 = [CCPhysicsJoint connectedPivotJointWithBodyA:body1 bodyB:body2 anchorA:ccp(rect.size.width/2.0, -rect.size.height/4.0)];
  501. joint3.breakingForce = -physics.gravity.y*body2.mass*1.1;
  502. }{
  503. CCNode *node1 = [CCNode node];
  504. node1.position = ccp(400, 200);
  505. CCPhysicsBody *body1 = node1.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
  506. body1.type = CCPhysicsBodyTypeStatic;
  507. [physics addChild:node1];
  508. CCNode *node2 = [CCNode node];
  509. node2.position = ccp(400, 100);
  510. CCPhysicsBody *body2 = node2.physicsBody = [CCPhysicsBody bodyWithRect:rect cornerRadius:0.0];
  511. [physics addChild:node2];
  512. joint4 = [CCPhysicsJoint connectedDistanceJointWithBodyA:body1 bodyB:body2 anchorA:ccp(rect.size.width/2.0, 0.0) anchorB:ccp(rect.size.width/2.0, rect.size.height)];
  513. joint4.breakingForce = -physics.gravity.y*body2.mass*1.1;
  514. }
  515. [physics onEnter];
  516. for(int i=0; i<100; i++){
  517. [physics fixedUpdate:1.0/60.0];
  518. }
  519. XCTAssert(!joint1.valid, @"");
  520. XCTAssert(!joint2.valid, @"");
  521. XCTAssert(joint3.valid, @"");
  522. XCTAssert(joint4.valid, @"");
  523. [physics onExit];
  524. }
  525. -(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair theStaticOne:(CCNode *)nodeA theDynamicOne:(CCNode *)nodeB
  526. {
  527. nodeB.physicsBody.type = CCPhysicsBodyTypeStatic;
  528. // TODO not sure if we should hide the deferred nature or not... Hrm.
  529. XCTAssertEqual(nodeB.physicsBody.type, CCPhysicsBodyTypeDynamic, @"");
  530. return FALSE;
  531. }
  532. -(void)testBodyTypeCollisions
  533. {
  534. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  535. physicsNode.collisionDelegate = self;
  536. physicsNode.gravity = ccp(0, -100);
  537. CCNode *node1 = [CCNode node];
  538. node1.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  539. node1.physicsBody.type = CCPhysicsBodyTypeStatic;
  540. node1.physicsBody.collisionType = @"theStaticOne";
  541. [physicsNode addChild:node1];
  542. CCNode *node2 = [CCNode node];
  543. node2.position = ccp(0, 10);
  544. node2.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  545. node2.physicsBody.type = CCPhysicsBodyTypeDynamic;
  546. node2.physicsBody.collisionType = @"theDynamicOne";
  547. [physicsNode addChild:node2];
  548. // Force entering the scene to set up the physics objects.
  549. [physicsNode onEnter];
  550. // Step the physics for a while.
  551. for(int i=0; i<100; i++){
  552. [physicsNode fixedUpdate:1.0/100.0];
  553. }
  554. XCTAssertEqual(node2.physicsBody.type, CCPhysicsBodyTypeStatic, @"");
  555. [physicsNode onExit];
  556. }
  557. -(void)testBodyEachCollisionPair
  558. {
  559. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  560. physicsNode.gravity = ccp(0, -100);
  561. CCNode *node1 = [CCNode node];
  562. node1.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  563. node1.physicsBody.type = CCPhysicsBodyTypeStatic;
  564. [physicsNode addChild:node1];
  565. CCNode *node2 = [CCNode node];
  566. node2.position = ccp(0, 10);
  567. node2.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1.0 andCenter:CGPointZero];
  568. node2.physicsBody.type = CCPhysicsBodyTypeDynamic;
  569. [physicsNode addChild:node2];
  570. // Force entering the scene to set up the physics objects.
  571. [physicsNode onEnter];
  572. // Step the physics for a while.
  573. for(int i=0; i<100; i++){
  574. [physicsNode fixedUpdate:1.0/100.0];
  575. }
  576. __block BOOL check = NO;
  577. [node1.physicsBody eachCollisionPair:^(CCPhysicsCollisionPair *pair) {
  578. CCPhysicsShape *a, *b; [pair shapeA:&a shapeB:&b];
  579. check = (
  580. (a.node == node1 && b.node == node2) ||
  581. (b.node == node1 && a.node == node2)
  582. );
  583. }];
  584. XCTAssert(check, @"The objects should have had a collision pair listed between them.");
  585. [physicsNode onExit];
  586. }
  587. //Focusing on Position.
  588. -(void)testKineticBodyBasic1
  589. {
  590. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  591. physicsNode.collisionDelegate = self;
  592. physicsNode.gravity = ccp(0, 0);
  593. CGPoint node0Pos = ccp(100.0f,0.0f);
  594. CCNode *node0 = [CCNode node];
  595. node0.position = node0Pos;
  596. node0.name = @"node0";
  597. [physicsNode addChild:node0];
  598. CCPhysicsBody * body1 = [CCPhysicsBody bodyWithRect:CGRectMake(0, 0, 60, 20) cornerRadius:0];
  599. CGPoint node1Pos = ccp(-25, 0);
  600. CCNode *node1 = [CCNode node];
  601. node1.physicsBody = body1;
  602. node1.physicsBody.type = CCPhysicsBodyTypeStatic;
  603. node1.physicsBody.collisionType = @"theStaticOne";
  604. node1.name = @"node1";
  605. node1.position = node1Pos;
  606. node1.contentSize = CGSizeMake(60, 20);
  607. node1.anchorPoint = ccp(0.5f,0.5f);
  608. [node0 addChild:node1];
  609. // Force entering the scene to set up the physics objects.
  610. [physicsNode onEnter];
  611. // Step the physics for a while.
  612. const int KineticCount = 50;
  613. //Test translation.
  614. for(int i=0; i<100; i++)
  615. {
  616. if(i < KineticCount)
  617. {
  618. node0.position = ccp(node0Pos.x + (i + 1), node0Pos.y);
  619. }
  620. [physicsNode fixedUpdate:1.0/100.0];
  621. if(i >= KineticCount)
  622. {
  623. XCTAssertTrue(body1.type != CCPhysicsBodyTypeKinematic,@"Should not be kinetic now.");
  624. XCTAssertTrue(ccpLength(body1.velocity) == 0.0f ,@"Should not have velocity.");
  625. }
  626. else
  627. {
  628. XCTAssertTrue(body1.type == CCPhysicsBodyTypeKinematic, @"Should be kinetic now");
  629. XCTAssertTrue(ccpLength(body1.velocity) > 0.0f ,@"Should have velocity.");
  630. XCTAssertTrue(body1.absolutePosition.x == (45.0f + (i + 1)), @"should be this value");
  631. }
  632. }
  633. }
  634. //Focusing on rotation.
  635. -(void)testKineticBodyBasic2
  636. {
  637. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  638. physicsNode.collisionDelegate = self;
  639. physicsNode.gravity = ccp(0, 0);
  640. CGPoint node0Pos = ccp(100.0f,0.0f);
  641. CCNode *node0 = [CCNode node];
  642. node0.position = node0Pos;
  643. node0.name = @"node0";
  644. [physicsNode addChild:node0];
  645. CCPhysicsBody * body1 = [CCPhysicsBody bodyWithRect:CGRectMake(0, 0, 60, 20) cornerRadius:0];
  646. CGPoint node1Pos = ccp(-25, 0);
  647. CCNode *node1 = [CCNode node];
  648. node1.physicsBody = body1;
  649. node1.physicsBody.type = CCPhysicsBodyTypeStatic;
  650. node1.physicsBody.collisionType = @"theStaticOne";
  651. node1.name = @"node1";
  652. node1.position = node1Pos;
  653. node1.contentSize = CGSizeMake(60, 20);
  654. node1.anchorPoint = ccp(0.5f,0.5f);
  655. [node0 addChild:node1];
  656. // Force entering the scene to set up the physics objects.
  657. [physicsNode onEnter];
  658. // Step the physics for a while.
  659. const int KineticCount = 50;
  660. //Test translation.
  661. for(int i=0; i<100; i++)
  662. {
  663. if(i < KineticCount)
  664. {
  665. node0.rotation = (i + 1) * 1.0f;
  666. node1.rotation = (i + 1) * 1.0f;
  667. }
  668. [physicsNode fixedUpdate:1.0/100.0];
  669. if(i >= KineticCount)
  670. {
  671. XCTAssertTrue(body1.type != CCPhysicsBodyTypeKinematic, @"Should not be kinetic now.");
  672. }
  673. else
  674. {
  675. XCTAssertTrue(body1.type == CCPhysicsBodyTypeKinematic, @"Should be kinetic now");
  676. XCTAssertEqualWithAccuracy(-CC_RADIANS_TO_DEGREES(body1.absoluteRadians),(i + 1) * 2.0f,0.01f, @"Should be 2x rotation because of parent.");
  677. }
  678. }
  679. //TODO on exit
  680. //TODO if node0->node1->node2->node3 and you detatch node1,that node0 can get unobservered.
  681. }
  682. //When a node graph that is the child of a physics node is added (onEnter) ensure all the actions
  683. //it subsuquently posesses are changed to fixed scheduled.
  684. -(void)testKineticNodeActionsBasic1
  685. {
  686. CCPhysicsNode *physicsNode = [CCPhysicsNode node];
  687. physicsNode.collisionDelegate = self;
  688. physicsNode.gravity = ccp(0, 0);
  689. CGPoint node0Pos = ccp(0.0f,0.0f);
  690. CCNode *node0 = [CCNode node];
  691. node0.position = node0Pos;
  692. node0.name = @"node0";
  693. node0.scale = 2.0f;
  694. [node0 runAction:[CCActionMoveBy actionWithDuration:10 position:ccp(100, 0)]];
  695. [physicsNode addChild:node0];
  696. CCPhysicsBody * body1 = [CCPhysicsBody bodyWithRect:CGRectMake(0, 0, 60, 20) cornerRadius:0];
  697. CGPoint node1Pos = ccp(0, 0);
  698. CCNode *node1 = [CCNode node];
  699. node1.physicsBody = body1;
  700. node1.physicsBody.type = CCPhysicsBodyTypeStatic;
  701. node1.physicsBody.collisionType = @"theStaticOne";
  702. node1.name = @"node1";
  703. node1.position = node1Pos;
  704. node1.contentSize = CGSizeMake(60, 20);
  705. node1.anchorPoint = ccp(0.0f,0.0f);
  706. [node0 addChild:node1];
  707. [node1 runAction:[CCActionMoveBy actionWithDuration:10 position:ccp(100, 0)]];
  708. // Force entering the scene to set up the physics objects.
  709. [physicsNode onEnter];
  710. CCScheduler * scheduler = [CCDirector sharedDirector].scheduler;
  711. scheduler.fixedUpdateInterval = 0.1f;
  712. [scheduler update:0.10f];// first tick
  713. const float accuracy = 1e-4;
  714. //test actions are fixed.
  715. for(int i = 0; i < 100; i++)
  716. {
  717. float desired = (float)i * 0.1f * 100.0f/10.0f + (float)i * 0.1f * 200.0f/10.0f;
  718. //NSLog(@"node1.position.x= %0.2f desired = %0.2f",body1.absolutePosition.x, desired);
  719. XCTAssertEqualWithAccuracy(body1.absolutePosition.x, desired , accuracy, @"Not in the write position");
  720. [scheduler update:0.10f];
  721. }
  722. }
  723. //TODO
  724. //Test : When a node is added to a scene graph, its actions are Fixed if its part of a PhysicsNode.
  725. -(void)testApplyImpulse
  726. {
  727. CCPhysicsNode *physics = [CCPhysicsNode node];
  728. [physics onEnter];
  729. {
  730. CCNode *node = [CCNode node];
  731. [physics addChild:node];
  732. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  733. node.physicsBody.mass = 5;
  734. node.physicsBody.velocity = ccp(10, 10);
  735. [node.physicsBody applyImpulse:ccp(5, 5)];
  736. XCTAssert(ccpDistance(ccp(11, 11), node.physicsBody.velocity) < 1e-5, @"");
  737. }{
  738. CCNode *node = [CCNode node];
  739. node.rotation = 90;
  740. [physics addChild:node];
  741. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  742. node.physicsBody.mass = 5;
  743. node.physicsBody.velocity = ccp(10, 10);
  744. [node.physicsBody applyImpulse:ccp(5, 5)];
  745. XCTAssert(ccpDistance(ccp(11, 11), node.physicsBody.velocity) < 1e-5, @"");
  746. }{
  747. CCNode *node = [CCNode node];
  748. node.position = ccp(20, 20);
  749. [physics addChild:node];
  750. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  751. node.physicsBody.mass = 5;
  752. node.physicsBody.velocity = ccp(10, 10);
  753. [node.physicsBody applyImpulse:ccp(5, 5) atWorldPoint:node.position];
  754. XCTAssert(ccpDistance(ccp(11, 11), node.physicsBody.velocity) < 1e-5, @"");
  755. }{
  756. CCNode *node = [CCNode node];
  757. node.position = ccp(20, 20);
  758. [physics addChild:node];
  759. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  760. node.physicsBody.mass = 5;
  761. node.physicsBody.velocity = ccp(10, 10);
  762. [node.physicsBody applyImpulse:ccp(5, 5) atLocalPoint:ccp(0, 0)];
  763. XCTAssert(ccpDistance(ccp(11, 11), node.physicsBody.velocity) < 1e-5, @"");
  764. }{
  765. CCNode *node = [CCNode node];
  766. node.position = ccp(20, 20);
  767. node.rotation = 90;
  768. [physics addChild:node];
  769. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  770. node.physicsBody.mass = 5;
  771. node.physicsBody.velocity = ccp(10, 10);
  772. [node.physicsBody applyImpulse:ccp(5, 0) atLocalPoint:ccp(0, 0)];
  773. XCTAssert(ccpDistance(ccp(10, 9), node.physicsBody.velocity) < 1e-5, @"");
  774. }{
  775. CCNode *node = [CCNode node];
  776. node.position = ccp(20, 20);
  777. node.rotation = 180;
  778. [physics addChild:node];
  779. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  780. node.physicsBody.mass = 5;
  781. node.physicsBody.velocity = ccp(10, 10);
  782. [node.physicsBody applyImpulse:ccp(5, 0) atLocalPoint:ccp(0, 1)];
  783. XCTAssert(ccpDistance(ccp(9, 10), node.physicsBody.velocity) < 1e-5, @"");
  784. XCTAssertEqualWithAccuracy(node.physicsBody.angularVelocity, -2, 1e-5, @"");
  785. }
  786. [physics onExit];
  787. }
  788. -(void)testApplyForce
  789. {
  790. CCPhysicsNode *physics = [CCPhysicsNode node];
  791. [physics onEnter];
  792. {
  793. CCNode *node = [CCNode node];
  794. [physics addChild:node];
  795. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  796. node.physicsBody.mass = 5;
  797. [node.physicsBody applyForce:ccp(5, 5)];
  798. XCTAssert(ccpDistance(ccp(5, 5), node.physicsBody.force) < 1e-5, @"");
  799. }{
  800. CCNode *node = [CCNode node];
  801. node.rotation = 90;
  802. [physics addChild:node];
  803. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  804. node.physicsBody.mass = 5;
  805. [node.physicsBody applyForce:ccp(5, 5)];
  806. XCTAssert(ccpDistance(ccp(5, 5), node.physicsBody.force) < 1e-5, @"");
  807. }{
  808. CCNode *node = [CCNode node];
  809. node.position = ccp(20, 20);
  810. [physics addChild:node];
  811. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  812. node.physicsBody.mass = 5;
  813. [node.physicsBody applyForce:ccp(5, 5) atWorldPoint:node.position];
  814. XCTAssert(ccpDistance(ccp(5, 5), node.physicsBody.force) < 1e-5, @"");
  815. }{
  816. CCNode *node = [CCNode node];
  817. node.position = ccp(20, 20);
  818. [physics addChild:node];
  819. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  820. node.physicsBody.mass = 5;
  821. [node.physicsBody applyForce:ccp(5, 5) atLocalPoint:ccp(0, 0)];
  822. XCTAssert(ccpDistance(ccp(5, 5), node.physicsBody.force) < 1e-5, @"");
  823. }{
  824. CCNode *node = [CCNode node];
  825. node.position = ccp(20, 20);
  826. node.rotation = 90;
  827. [physics addChild:node];
  828. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  829. node.physicsBody.mass = 5;
  830. [node.physicsBody applyForce:ccp(5, 0) atLocalPoint:ccp(0, 0)];
  831. XCTAssert(ccpDistance(ccp(0, -5), node.physicsBody.force) < 1e-5, @"");
  832. }{
  833. CCNode *node = [CCNode node];
  834. node.position = ccp(20, 20);
  835. node.rotation = 180;
  836. [physics addChild:node];
  837. node.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:1 andCenter:CGPointZero];
  838. node.physicsBody.mass = 5;
  839. [node.physicsBody applyForce:ccp(5, 0) atLocalPoint:ccp(0, 1)];
  840. XCTAssert(ccpDistance(ccp(-5, 0), node.physicsBody.force) < 1e-5, @"");
  841. XCTAssertEqualWithAccuracy(node.physicsBody.torque, -5, 1e-5, @"");
  842. }
  843. [physics onExit];
  844. }
  845. // TODO
  846. // * Check that body and shape settings are preserved through multiple add/remove cycles and are actually applied to the cpBody.
  847. // * Check that changing properties before and after adding to an active physics node updates the properties correctly.
  848. @end