/libs/cocos2d/CCNode.m

http://github.com/kstenerud/ObjectAL-for-iPhone · Objective C · 790 lines · 532 code · 171 blank · 87 comment · 94 complexity · 00619b2e559998abfbd0dbae37087c82 MD5 · raw file

  1. /*
  2. * cocos2d for iPhone: http://www.cocos2d-iphone.org
  3. *
  4. * Copyright (c) 2008-2010 Ricardo Quesada
  5. * Copyright (c) 2009 Valentin Milea
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. */
  25. #import "ccConfig.h"
  26. #import "CCNode.h"
  27. #import "CCCamera.h"
  28. #import "CCGrid.h"
  29. #import "CCScheduler.h"
  30. #import "ccMacros.h"
  31. #import "CCDirector.h"
  32. #import "CCActionManager.h"
  33. #import "Support/CGPointExtension.h"
  34. #import "Support/ccCArray.h"
  35. #import "Support/TransformUtils.h"
  36. #if CC_COCOSNODE_RENDER_SUBPIXEL
  37. #define RENDER_IN_SUBPIXEL
  38. #else
  39. #define RENDER_IN_SUBPIXEL (int)
  40. #endif
  41. @interface CCNode (Private)
  42. // lazy allocs
  43. -(void) childrenAlloc;
  44. // helper that reorder a child
  45. -(void) insertChild:(CCNode*)child z:(int)z;
  46. // used internally to alter the zOrder variable. DON'T call this method manually
  47. -(void) _setZOrder:(int) z;
  48. -(void) detachChild:(CCNode *)child cleanup:(BOOL)doCleanup;
  49. @end
  50. @implementation CCNode
  51. @synthesize children = children_;
  52. @synthesize visible=visible_;
  53. @synthesize parent=parent_;
  54. @synthesize grid=grid_;
  55. @synthesize zOrder=zOrder_;
  56. @synthesize tag=tag_;
  57. @synthesize vertexZ = vertexZ_;
  58. @synthesize isRunning=isRunning_;
  59. #pragma mark CCNode - Transform related properties
  60. @synthesize rotation=rotation_, scaleX=scaleX_, scaleY=scaleY_, position=position_;
  61. @synthesize anchorPointInPixels=anchorPointInPixels_, isRelativeAnchorPoint=isRelativeAnchorPoint_;
  62. @synthesize userData;
  63. // getters synthesized, setters explicit
  64. -(void) setRotation: (float)newRotation
  65. {
  66. rotation_ = newRotation;
  67. isTransformDirty_ = isInverseDirty_ = YES;
  68. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  69. isTransformGLDirty_ = YES;
  70. #endif
  71. }
  72. -(void) setScaleX: (float)newScaleX
  73. {
  74. scaleX_ = newScaleX;
  75. isTransformDirty_ = isInverseDirty_ = YES;
  76. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  77. isTransformGLDirty_ = YES;
  78. #endif
  79. }
  80. -(void) setScaleY: (float)newScaleY
  81. {
  82. scaleY_ = newScaleY;
  83. isTransformDirty_ = isInverseDirty_ = YES;
  84. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  85. isTransformGLDirty_ = YES;
  86. #endif
  87. }
  88. -(void) setPosition: (CGPoint)newPosition
  89. {
  90. position_ = newPosition;
  91. isTransformDirty_ = isInverseDirty_ = YES;
  92. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  93. isTransformGLDirty_ = YES;
  94. #endif
  95. }
  96. -(void) setIsRelativeAnchorPoint: (BOOL)newValue
  97. {
  98. isRelativeAnchorPoint_ = newValue;
  99. isTransformDirty_ = isInverseDirty_ = YES;
  100. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  101. isTransformGLDirty_ = YES;
  102. #endif
  103. }
  104. -(void) setAnchorPoint:(CGPoint)point
  105. {
  106. if( ! CGPointEqualToPoint(point, anchorPoint_) ) {
  107. anchorPoint_ = point;
  108. anchorPointInPixels_ = ccp( contentSize_.width * anchorPoint_.x, contentSize_.height * anchorPoint_.y );
  109. isTransformDirty_ = isInverseDirty_ = YES;
  110. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  111. isTransformGLDirty_ = YES;
  112. #endif
  113. }
  114. }
  115. -(CGPoint) anchorPoint
  116. {
  117. return anchorPoint_;
  118. }
  119. -(void) setContentSize:(CGSize)size
  120. {
  121. if( ! CGSizeEqualToSize(size, contentSize_) ) {
  122. contentSize_ = size;
  123. anchorPointInPixels_ = ccp( contentSize_.width * anchorPoint_.x, contentSize_.height * anchorPoint_.y );
  124. isTransformDirty_ = isInverseDirty_ = YES;
  125. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  126. isTransformGLDirty_ = YES;
  127. #endif
  128. }
  129. }
  130. -(CGSize) contentSize
  131. {
  132. return contentSize_;
  133. }
  134. - (CGRect) boundingBox
  135. {
  136. CGRect rect = CGRectMake(0, 0, contentSize_.width, contentSize_.height);
  137. return CGRectApplyAffineTransform(rect, [self nodeToParentTransform]);
  138. }
  139. -(float) scale
  140. {
  141. NSAssert( scaleX_ == scaleY_, @"CCNode#scale. ScaleX != ScaleY. Don't know which one to return");
  142. return scaleX_;
  143. }
  144. -(void) setScale:(float) s
  145. {
  146. scaleX_ = scaleY_ = s;
  147. isTransformDirty_ = isInverseDirty_ = YES;
  148. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  149. isTransformGLDirty_ = YES;
  150. #endif
  151. }
  152. #pragma mark CCNode - Init & cleanup
  153. +(id) node
  154. {
  155. return [[[self alloc] init] autorelease];
  156. }
  157. -(id) init
  158. {
  159. if ((self=[super init]) ) {
  160. isRunning_ = NO;
  161. rotation_ = 0.0f;
  162. scaleX_ = scaleY_ = 1.0f;
  163. position_ = CGPointZero;
  164. anchorPointInPixels_ = anchorPoint_ = CGPointZero;
  165. contentSize_ = CGSizeZero;
  166. // "whole screen" objects. like Scenes and Layers, should set isRelativeAnchorPoint to NO
  167. isRelativeAnchorPoint_ = YES;
  168. isTransformDirty_ = isInverseDirty_ = YES;
  169. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  170. isTransformGLDirty_ = YES;
  171. #endif
  172. vertexZ_ = 0;
  173. grid_ = nil;
  174. visible_ = YES;
  175. tag_ = kCCNodeTagInvalid;
  176. zOrder_ = 0;
  177. // lazy alloc
  178. camera_ = nil;
  179. // children (lazy allocs)
  180. children_ = nil;
  181. // userData is always inited as nil
  182. userData = nil;
  183. }
  184. return self;
  185. }
  186. - (void)cleanup
  187. {
  188. // actions
  189. [self stopAllActions];
  190. [self unscheduleAllSelectors];
  191. // timers
  192. [children_ makeObjectsPerformSelector:@selector(cleanup)];
  193. }
  194. - (NSString*) description
  195. {
  196. return [NSString stringWithFormat:@"<%@ = %08X | Tag = %i>", [self class], self, tag_];
  197. }
  198. - (void) dealloc
  199. {
  200. CCLOGINFO( @"cocos2d: deallocing %@", self);
  201. // attributes
  202. [camera_ release];
  203. [grid_ release];
  204. // children
  205. CCNode *child;
  206. CCARRAY_FOREACH(children_, child)
  207. child.parent = nil;
  208. [children_ release];
  209. [super dealloc];
  210. }
  211. #pragma mark CCNode Composition
  212. -(void) childrenAlloc
  213. {
  214. children_ = [[CCArray alloc] initWithCapacity:4];
  215. }
  216. // camera: lazy alloc
  217. -(CCCamera*) camera
  218. {
  219. if( ! camera_ ) {
  220. camera_ = [[CCCamera alloc] init];
  221. // by default, center camera at the Sprite's anchor point
  222. // [camera_ setCenterX:anchorPointInPixels_.x centerY:anchorPointInPixels_.y centerZ:0];
  223. // [camera_ setEyeX:anchorPointInPixels_.x eyeY:anchorPointInPixels_.y eyeZ:1];
  224. // [camera_ setCenterX:0 centerY:0 centerZ:0];
  225. // [camera_ setEyeX:0 eyeY:0 eyeZ:1];
  226. }
  227. return camera_;
  228. }
  229. -(CCNode*) getChildByTag:(int) aTag
  230. {
  231. NSAssert( aTag != kCCNodeTagInvalid, @"Invalid tag");
  232. CCNode *node;
  233. CCARRAY_FOREACH(children_, node){
  234. if( node.tag == aTag )
  235. return node;
  236. }
  237. // not found
  238. return nil;
  239. }
  240. /* "add" logic MUST only be on this method
  241. * If a class want's to extend the 'addChild' behaviour it only needs
  242. * to override this method
  243. */
  244. -(id) addChild: (CCNode*) child z:(int)z tag:(int) aTag
  245. {
  246. NSAssert( child != nil, @"Argument must be non-nil");
  247. NSAssert( child.parent == nil, @"child already added. It can't be added again");
  248. if( ! children_ )
  249. [self childrenAlloc];
  250. [self insertChild:child z:z];
  251. child.tag = aTag;
  252. [child setParent: self];
  253. if( isRunning_ )
  254. [child onEnter];
  255. return self;
  256. }
  257. -(id) addChild: (CCNode*) child z:(int)z
  258. {
  259. NSAssert( child != nil, @"Argument must be non-nil");
  260. return [self addChild:child z:z tag:child.tag];
  261. }
  262. -(id) addChild: (CCNode*) child
  263. {
  264. NSAssert( child != nil, @"Argument must be non-nil");
  265. return [self addChild:child z:child.zOrder tag:child.tag];
  266. }
  267. -(void) removeFromParentAndCleanup:(BOOL)cleanup
  268. {
  269. [parent_ removeChild:self cleanup:cleanup];
  270. }
  271. /* "remove" logic MUST only be on this method
  272. * If a class want's to extend the 'removeChild' behavior it only needs
  273. * to override this method
  274. */
  275. -(void) removeChild: (CCNode*)child cleanup:(BOOL)cleanup
  276. {
  277. // explicit nil handling
  278. if (child == nil)
  279. return;
  280. if ( [children_ containsObject:child] )
  281. [self detachChild:child cleanup:cleanup];
  282. }
  283. -(void) removeChildByTag:(int)aTag cleanup:(BOOL)cleanup
  284. {
  285. NSAssert( aTag != kCCNodeTagInvalid, @"Invalid tag");
  286. CCNode *child = [self getChildByTag:aTag];
  287. if (child == nil)
  288. CCLOG(@"cocos2d: removeChildByTag: child not found!");
  289. else
  290. [self removeChild:child cleanup:cleanup];
  291. }
  292. -(void) removeAllChildrenWithCleanup:(BOOL)cleanup
  293. {
  294. // not using detachChild improves speed here
  295. CCNode *c;
  296. CCARRAY_FOREACH(children_, c)
  297. {
  298. // IMPORTANT:
  299. // -1st do onExit
  300. // -2nd cleanup
  301. if (isRunning_)
  302. [c onExit];
  303. if (cleanup)
  304. [c cleanup];
  305. // set parent nil at the end (issue #476)
  306. [c setParent:nil];
  307. }
  308. [children_ removeAllObjects];
  309. }
  310. -(void) detachChild:(CCNode *)child cleanup:(BOOL)doCleanup
  311. {
  312. // IMPORTANT:
  313. // -1st do onExit
  314. // -2nd cleanup
  315. if (isRunning_)
  316. [child onExit];
  317. // If you don't do cleanup, the child's actions will not get removed and the
  318. // its scheduledSelectors_ dict will not get released!
  319. if (doCleanup)
  320. [child cleanup];
  321. // set parent nil at the end (issue #476)
  322. [child setParent:nil];
  323. [children_ removeObject:child];
  324. }
  325. // used internally to alter the zOrder variable. DON'T call this method manually
  326. -(void) _setZOrder:(int) z
  327. {
  328. zOrder_ = z;
  329. }
  330. // helper used by reorderChild & add
  331. -(void) insertChild:(CCNode*)child z:(int)z
  332. {
  333. int index=0;
  334. BOOL added = NO;
  335. CCNode *a;
  336. CCARRAY_FOREACH(children_, a){
  337. if ( a.zOrder > z ) {
  338. added = YES;
  339. [ children_ insertObject:child atIndex:index];
  340. break;
  341. }
  342. index++;
  343. }
  344. if( ! added )
  345. [children_ addObject:child];
  346. [child _setZOrder:z];
  347. }
  348. -(void) reorderChild:(CCNode*) child z:(int)z
  349. {
  350. NSAssert( child != nil, @"Child must be non-nil");
  351. [child retain];
  352. [children_ removeObject:child];
  353. [self insertChild:child z:z];
  354. [child release];
  355. }
  356. #pragma mark CCNode Draw
  357. -(void) draw
  358. {
  359. // override me
  360. // Only use this function to draw your staff.
  361. // DON'T draw your stuff outside this method
  362. }
  363. -(void) visit
  364. {
  365. // quick return if not visible
  366. if (!visible_)
  367. return;
  368. glPushMatrix();
  369. if ( grid_ && grid_.active) {
  370. [grid_ beforeDraw];
  371. [self transformAncestors];
  372. }
  373. [self transform];
  374. if(children_) {
  375. ccArray *arrayData = children_->data;
  376. unsigned int i=0;
  377. // draw children zOrder < 0
  378. for( ; i < arrayData->num; i++ ) {
  379. CCNode *child = arrayData->arr[i];
  380. if ( [child zOrder] < 0 ) {
  381. [child visit];
  382. } else
  383. break;
  384. }
  385. // self draw
  386. [self draw];
  387. // draw children zOrder >= 0
  388. for( ; i < arrayData->num; i++ ) {
  389. CCNode *child = arrayData->arr[i];
  390. [child visit];
  391. }
  392. } else
  393. [self draw];
  394. if ( grid_ && grid_.active)
  395. [grid_ afterDraw:self];
  396. glPopMatrix();
  397. }
  398. #pragma mark CCNode - Transformations
  399. -(void) transformAncestors
  400. {
  401. if( parent_ ) {
  402. [parent_ transformAncestors];
  403. [parent_ transform];
  404. }
  405. }
  406. -(void) transform
  407. {
  408. // transformations
  409. #if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX
  410. // BEGIN alternative -- using cached transform
  411. //
  412. if( isTransformGLDirty_ ) {
  413. CGAffineTransform t = [self nodeToParentTransform];
  414. CGAffineToGL(&t, transformGL_);
  415. isTransformGLDirty_ = NO;
  416. }
  417. glMultMatrixf(transformGL_);
  418. if( vertexZ_ )
  419. glTranslatef(0, 0, vertexZ_);
  420. // XXX: Expensive calls. Camera should be integrated into the cached affine matrix
  421. if ( camera_ && !(grid_ && grid_.active) ) {
  422. BOOL translate = (anchorPointInPixels_.x != 0.0f || anchorPointInPixels_.y != 0.0f);
  423. if( translate )
  424. glTranslatef(RENDER_IN_SUBPIXEL(anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(anchorPointInPixels_.y), 0);
  425. [camera_ locate];
  426. if( translate )
  427. glTranslatef(RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0);
  428. }
  429. // END alternative
  430. #else
  431. // BEGIN original implementation
  432. //
  433. // translate
  434. if ( isRelativeAnchorPoint_ && (anchorPointInPixels_.x != 0 || anchorPointInPixels_.y != 0 ) )
  435. glTranslatef( RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0);
  436. if (anchorPointInPixels_.x != 0 || anchorPointInPixels_.y != 0)
  437. glTranslatef( RENDER_IN_SUBPIXEL(position_.x + anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(position_.y + anchorPointInPixels_.y), vertexZ_);
  438. else if ( position_.x !=0 || position_.y !=0 || vertexZ_ != 0)
  439. glTranslatef( RENDER_IN_SUBPIXEL(position_.x), RENDER_IN_SUBPIXEL(position_.y), vertexZ_ );
  440. // rotate
  441. if (rotation_ != 0.0f )
  442. glRotatef( -rotation_, 0.0f, 0.0f, 1.0f );
  443. // scale
  444. if (scaleX_ != 1.0f || scaleY_ != 1.0f)
  445. glScalef( scaleX_, scaleY_, 1.0f );
  446. if ( camera_ && !(grid_ && grid_.active) )
  447. [camera_ locate];
  448. // restore and re-position point
  449. if (anchorPointInPixels_.x != 0.0f || anchorPointInPixels_.y != 0.0f)
  450. glTranslatef(RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0);
  451. //
  452. // END original implementation
  453. #endif
  454. }
  455. #pragma mark CCNode SceneManagement
  456. -(void) onEnter
  457. {
  458. [children_ makeObjectsPerformSelector:@selector(onEnter)];
  459. [self resumeSchedulerAndActions];
  460. isRunning_ = YES;
  461. }
  462. -(void) onEnterTransitionDidFinish
  463. {
  464. [children_ makeObjectsPerformSelector:@selector(onEnterTransitionDidFinish)];
  465. }
  466. -(void) onExit
  467. {
  468. [self pauseSchedulerAndActions];
  469. isRunning_ = NO;
  470. [children_ makeObjectsPerformSelector:@selector(onExit)];
  471. }
  472. #pragma mark CCNode Actions
  473. -(CCAction*) runAction:(CCAction*) action
  474. {
  475. NSAssert( action != nil, @"Argument must be non-nil");
  476. [[CCActionManager sharedManager] addAction:action target:self paused:!isRunning_];
  477. return action;
  478. }
  479. -(void) stopAllActions
  480. {
  481. [[CCActionManager sharedManager] removeAllActionsFromTarget:self];
  482. }
  483. -(void) stopAction: (CCAction*) action
  484. {
  485. [[CCActionManager sharedManager] removeAction:action];
  486. }
  487. -(void) stopActionByTag:(int)aTag
  488. {
  489. NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
  490. [[CCActionManager sharedManager] removeActionByTag:aTag target:self];
  491. }
  492. -(CCAction*) getActionByTag:(int) aTag
  493. {
  494. NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag");
  495. return [[CCActionManager sharedManager] getActionByTag:aTag target:self];
  496. }
  497. -(int) numberOfRunningActions
  498. {
  499. return [[CCActionManager sharedManager] numberOfRunningActionsInTarget:self];
  500. }
  501. #pragma mark CCNode - Callbacks
  502. -(void) scheduleUpdate
  503. {
  504. [self scheduleUpdateWithPriority:0];
  505. }
  506. -(void) scheduleUpdateWithPriority:(int)priority
  507. {
  508. [[CCScheduler sharedScheduler] scheduleUpdateForTarget:self priority:priority paused:!isRunning_];
  509. }
  510. -(void) unscheduleUpdate
  511. {
  512. [[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self];
  513. }
  514. -(void) schedule:(SEL)selector
  515. {
  516. [self schedule:selector interval:0];
  517. }
  518. -(void) schedule:(SEL)selector interval:(ccTime)interval
  519. {
  520. NSAssert( selector != nil, @"Argument must be non-nil");
  521. NSAssert( interval >=0, @"Arguemnt must be positive");
  522. [[CCScheduler sharedScheduler] scheduleSelector:selector forTarget:self interval:interval paused:!isRunning_];
  523. }
  524. -(void) unschedule:(SEL)selector
  525. {
  526. // explicit nil handling
  527. if (selector == nil)
  528. return;
  529. [[CCScheduler sharedScheduler] unscheduleSelector:selector forTarget:self];
  530. }
  531. -(void) unscheduleAllSelectors
  532. {
  533. [[CCScheduler sharedScheduler] unscheduleAllSelectorsForTarget:self];
  534. }
  535. - (void) resumeSchedulerAndActions
  536. {
  537. [[CCScheduler sharedScheduler] resumeTarget:self];
  538. [[CCActionManager sharedManager] resumeTarget:self];
  539. }
  540. - (void) pauseSchedulerAndActions
  541. {
  542. [[CCScheduler sharedScheduler] pauseTarget:self];
  543. [[CCActionManager sharedManager] pauseTarget:self];
  544. }
  545. #pragma mark CCNode Transform
  546. - (CGAffineTransform)nodeToParentTransform
  547. {
  548. if ( isTransformDirty_ ) {
  549. transform_ = CGAffineTransformIdentity;
  550. if ( !isRelativeAnchorPoint_ && !CGPointEqualToPoint(anchorPointInPixels_, CGPointZero) )
  551. transform_ = CGAffineTransformTranslate(transform_, anchorPointInPixels_.x, anchorPointInPixels_.y);
  552. if( ! CGPointEqualToPoint(position_, CGPointZero) )
  553. transform_ = CGAffineTransformTranslate(transform_, position_.x, position_.y);
  554. if( rotation_ != 0 )
  555. transform_ = CGAffineTransformRotate(transform_, -CC_DEGREES_TO_RADIANS(rotation_));
  556. if( ! (scaleX_ == 1 && scaleY_ == 1) )
  557. transform_ = CGAffineTransformScale(transform_, scaleX_, scaleY_);
  558. if( ! CGPointEqualToPoint(anchorPointInPixels_, CGPointZero) )
  559. transform_ = CGAffineTransformTranslate(transform_, -anchorPointInPixels_.x, -anchorPointInPixels_.y);
  560. isTransformDirty_ = NO;
  561. }
  562. return transform_;
  563. }
  564. - (CGAffineTransform)parentToNodeTransform
  565. {
  566. if ( isInverseDirty_ ) {
  567. inverse_ = CGAffineTransformInvert([self nodeToParentTransform]);
  568. isInverseDirty_ = NO;
  569. }
  570. return inverse_;
  571. }
  572. - (CGAffineTransform)nodeToWorldTransform
  573. {
  574. CGAffineTransform t = [self nodeToParentTransform];
  575. for (CCNode *p = parent_; p != nil; p = p.parent)
  576. t = CGAffineTransformConcat(t, [p nodeToParentTransform]);
  577. return t;
  578. }
  579. - (CGAffineTransform)worldToNodeTransform
  580. {
  581. return CGAffineTransformInvert([self nodeToWorldTransform]);
  582. }
  583. - (CGPoint)convertToNodeSpace:(CGPoint)worldPoint
  584. {
  585. return CGPointApplyAffineTransform(worldPoint, [self worldToNodeTransform]);
  586. }
  587. - (CGPoint)convertToWorldSpace:(CGPoint)nodePoint
  588. {
  589. return CGPointApplyAffineTransform(nodePoint, [self nodeToWorldTransform]);
  590. }
  591. - (CGPoint)convertToNodeSpaceAR:(CGPoint)worldPoint
  592. {
  593. CGPoint nodePoint = [self convertToNodeSpace:worldPoint];
  594. return ccpSub(nodePoint, anchorPointInPixels_);
  595. }
  596. - (CGPoint)convertToWorldSpaceAR:(CGPoint)nodePoint
  597. {
  598. nodePoint = ccpAdd(nodePoint, anchorPointInPixels_);
  599. return [self convertToWorldSpace:nodePoint];
  600. }
  601. - (CGPoint)convertToWindowSpace:(CGPoint)nodePoint
  602. {
  603. CGPoint worldPoint = [self convertToWorldSpace:nodePoint];
  604. return [[CCDirector sharedDirector] convertToUI:worldPoint];
  605. }
  606. // convenience methods which take a UITouch instead of CGPoint
  607. - (CGPoint)convertTouchToNodeSpace:(UITouch *)touch
  608. {
  609. CGPoint point = [touch locationInView: [touch view]];
  610. point = [[CCDirector sharedDirector] convertToGL: point];
  611. return [self convertToNodeSpace:point];
  612. }
  613. - (CGPoint)convertTouchToNodeSpaceAR:(UITouch *)touch
  614. {
  615. CGPoint point = [touch locationInView: [touch view]];
  616. point = [[CCDirector sharedDirector] convertToGL: point];
  617. return [self convertToNodeSpaceAR:point];
  618. }
  619. @end