/libs/cocos2d/CCNode.m
Objective C | 790 lines | 532 code | 171 blank | 87 comment | 94 complexity | 00619b2e559998abfbd0dbae37087c82 MD5 | raw file
Possible License(s): Apache-2.0
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 26 27 28#import "ccConfig.h" 29#import "CCNode.h" 30#import "CCCamera.h" 31#import "CCGrid.h" 32#import "CCScheduler.h" 33#import "ccMacros.h" 34#import "CCDirector.h" 35#import "CCActionManager.h" 36#import "Support/CGPointExtension.h" 37#import "Support/ccCArray.h" 38#import "Support/TransformUtils.h" 39 40 41#if CC_COCOSNODE_RENDER_SUBPIXEL 42#define RENDER_IN_SUBPIXEL 43#else 44#define RENDER_IN_SUBPIXEL (int) 45#endif 46 47@interface CCNode (Private) 48// lazy allocs 49-(void) childrenAlloc; 50// helper that reorder a child 51-(void) insertChild:(CCNode*)child z:(int)z; 52// used internally to alter the zOrder variable. DON'T call this method manually 53-(void) _setZOrder:(int) z; 54-(void) detachChild:(CCNode *)child cleanup:(BOOL)doCleanup; 55@end 56 57@implementation CCNode 58 59@synthesize children = children_; 60@synthesize visible=visible_; 61@synthesize parent=parent_; 62@synthesize grid=grid_; 63@synthesize zOrder=zOrder_; 64@synthesize tag=tag_; 65@synthesize vertexZ = vertexZ_; 66@synthesize isRunning=isRunning_; 67 68#pragma mark CCNode - Transform related properties 69 70@synthesize rotation=rotation_, scaleX=scaleX_, scaleY=scaleY_, position=position_; 71@synthesize anchorPointInPixels=anchorPointInPixels_, isRelativeAnchorPoint=isRelativeAnchorPoint_; 72@synthesize userData; 73 74// getters synthesized, setters explicit 75-(void) setRotation: (float)newRotation 76{ 77 rotation_ = newRotation; 78 isTransformDirty_ = isInverseDirty_ = YES; 79#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 80 isTransformGLDirty_ = YES; 81#endif 82} 83 84-(void) setScaleX: (float)newScaleX 85{ 86 scaleX_ = newScaleX; 87 isTransformDirty_ = isInverseDirty_ = YES; 88#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 89 isTransformGLDirty_ = YES; 90#endif 91} 92 93-(void) setScaleY: (float)newScaleY 94{ 95 scaleY_ = newScaleY; 96 isTransformDirty_ = isInverseDirty_ = YES; 97#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 98 isTransformGLDirty_ = YES; 99#endif 100} 101 102-(void) setPosition: (CGPoint)newPosition 103{ 104 position_ = newPosition; 105 isTransformDirty_ = isInverseDirty_ = YES; 106#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 107 isTransformGLDirty_ = YES; 108#endif 109} 110 111-(void) setIsRelativeAnchorPoint: (BOOL)newValue 112{ 113 isRelativeAnchorPoint_ = newValue; 114 isTransformDirty_ = isInverseDirty_ = YES; 115#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 116 isTransformGLDirty_ = YES; 117#endif 118} 119 120-(void) setAnchorPoint:(CGPoint)point 121{ 122 if( ! CGPointEqualToPoint(point, anchorPoint_) ) { 123 anchorPoint_ = point; 124 anchorPointInPixels_ = ccp( contentSize_.width * anchorPoint_.x, contentSize_.height * anchorPoint_.y ); 125 isTransformDirty_ = isInverseDirty_ = YES; 126#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 127 isTransformGLDirty_ = YES; 128#endif 129 } 130} 131-(CGPoint) anchorPoint 132{ 133 return anchorPoint_; 134} 135 136-(void) setContentSize:(CGSize)size 137{ 138 if( ! CGSizeEqualToSize(size, contentSize_) ) { 139 contentSize_ = size; 140 anchorPointInPixels_ = ccp( contentSize_.width * anchorPoint_.x, contentSize_.height * anchorPoint_.y ); 141 isTransformDirty_ = isInverseDirty_ = YES; 142#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 143 isTransformGLDirty_ = YES; 144#endif 145 } 146} 147-(CGSize) contentSize 148{ 149 return contentSize_; 150} 151 152- (CGRect) boundingBox 153{ 154 CGRect rect = CGRectMake(0, 0, contentSize_.width, contentSize_.height); 155 return CGRectApplyAffineTransform(rect, [self nodeToParentTransform]); 156} 157 158-(float) scale 159{ 160 NSAssert( scaleX_ == scaleY_, @"CCNode#scale. ScaleX != ScaleY. Don't know which one to return"); 161 return scaleX_; 162} 163 164-(void) setScale:(float) s 165{ 166 scaleX_ = scaleY_ = s; 167 isTransformDirty_ = isInverseDirty_ = YES; 168#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 169 isTransformGLDirty_ = YES; 170#endif 171} 172 173#pragma mark CCNode - Init & cleanup 174 175+(id) node 176{ 177 return [[[self alloc] init] autorelease]; 178} 179 180-(id) init 181{ 182 if ((self=[super init]) ) { 183 184 isRunning_ = NO; 185 186 rotation_ = 0.0f; 187 scaleX_ = scaleY_ = 1.0f; 188 position_ = CGPointZero; 189 anchorPointInPixels_ = anchorPoint_ = CGPointZero; 190 contentSize_ = CGSizeZero; 191 192 193 // "whole screen" objects. like Scenes and Layers, should set isRelativeAnchorPoint to NO 194 isRelativeAnchorPoint_ = YES; 195 196 isTransformDirty_ = isInverseDirty_ = YES; 197#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 198 isTransformGLDirty_ = YES; 199#endif 200 201 vertexZ_ = 0; 202 203 grid_ = nil; 204 205 visible_ = YES; 206 207 tag_ = kCCNodeTagInvalid; 208 209 zOrder_ = 0; 210 211 // lazy alloc 212 camera_ = nil; 213 214 // children (lazy allocs) 215 children_ = nil; 216 217 // userData is always inited as nil 218 userData = nil; 219 } 220 221 return self; 222} 223 224- (void)cleanup 225{ 226 // actions 227 [self stopAllActions]; 228 [self unscheduleAllSelectors]; 229 230 // timers 231 232 [children_ makeObjectsPerformSelector:@selector(cleanup)]; 233} 234 235- (NSString*) description 236{ 237 return [NSString stringWithFormat:@"<%@ = %08X | Tag = %i>", [self class], self, tag_]; 238} 239 240- (void) dealloc 241{ 242 CCLOGINFO( @"cocos2d: deallocing %@", self); 243 244 // attributes 245 [camera_ release]; 246 247 [grid_ release]; 248 249 // children 250 251 CCNode *child; 252 CCARRAY_FOREACH(children_, child) 253 child.parent = nil; 254 255 [children_ release]; 256 257 [super dealloc]; 258} 259 260#pragma mark CCNode Composition 261 262-(void) childrenAlloc 263{ 264 children_ = [[CCArray alloc] initWithCapacity:4]; 265} 266 267// camera: lazy alloc 268-(CCCamera*) camera 269{ 270 if( ! camera_ ) { 271 camera_ = [[CCCamera alloc] init]; 272 273 // by default, center camera at the Sprite's anchor point 274 // [camera_ setCenterX:anchorPointInPixels_.x centerY:anchorPointInPixels_.y centerZ:0]; 275 // [camera_ setEyeX:anchorPointInPixels_.x eyeY:anchorPointInPixels_.y eyeZ:1]; 276 277 // [camera_ setCenterX:0 centerY:0 centerZ:0]; 278 // [camera_ setEyeX:0 eyeY:0 eyeZ:1]; 279 280 } 281 282 return camera_; 283} 284 285-(CCNode*) getChildByTag:(int) aTag 286{ 287 NSAssert( aTag != kCCNodeTagInvalid, @"Invalid tag"); 288 289 CCNode *node; 290 CCARRAY_FOREACH(children_, node){ 291 if( node.tag == aTag ) 292 return node; 293 } 294 // not found 295 return nil; 296} 297 298/* "add" logic MUST only be on this method 299 * If a class want's to extend the 'addChild' behaviour it only needs 300 * to override this method 301 */ 302-(id) addChild: (CCNode*) child z:(int)z tag:(int) aTag 303{ 304 NSAssert( child != nil, @"Argument must be non-nil"); 305 NSAssert( child.parent == nil, @"child already added. It can't be added again"); 306 307 if( ! children_ ) 308 [self childrenAlloc]; 309 310 [self insertChild:child z:z]; 311 312 child.tag = aTag; 313 314 [child setParent: self]; 315 316 if( isRunning_ ) 317 [child onEnter]; 318 return self; 319} 320 321-(id) addChild: (CCNode*) child z:(int)z 322{ 323 NSAssert( child != nil, @"Argument must be non-nil"); 324 return [self addChild:child z:z tag:child.tag]; 325} 326 327-(id) addChild: (CCNode*) child 328{ 329 NSAssert( child != nil, @"Argument must be non-nil"); 330 return [self addChild:child z:child.zOrder tag:child.tag]; 331} 332 333-(void) removeFromParentAndCleanup:(BOOL)cleanup 334{ 335 [parent_ removeChild:self cleanup:cleanup]; 336} 337 338/* "remove" logic MUST only be on this method 339 * If a class want's to extend the 'removeChild' behavior it only needs 340 * to override this method 341 */ 342-(void) removeChild: (CCNode*)child cleanup:(BOOL)cleanup 343{ 344 // explicit nil handling 345 if (child == nil) 346 return; 347 348 if ( [children_ containsObject:child] ) 349 [self detachChild:child cleanup:cleanup]; 350} 351 352-(void) removeChildByTag:(int)aTag cleanup:(BOOL)cleanup 353{ 354 NSAssert( aTag != kCCNodeTagInvalid, @"Invalid tag"); 355 356 CCNode *child = [self getChildByTag:aTag]; 357 358 if (child == nil) 359 CCLOG(@"cocos2d: removeChildByTag: child not found!"); 360 else 361 [self removeChild:child cleanup:cleanup]; 362} 363 364-(void) removeAllChildrenWithCleanup:(BOOL)cleanup 365{ 366 // not using detachChild improves speed here 367 CCNode *c; 368 CCARRAY_FOREACH(children_, c) 369 { 370 // IMPORTANT: 371 // -1st do onExit 372 // -2nd cleanup 373 if (isRunning_) 374 [c onExit]; 375 376 if (cleanup) 377 [c cleanup]; 378 379 // set parent nil at the end (issue #476) 380 [c setParent:nil]; 381 } 382 383 [children_ removeAllObjects]; 384} 385 386-(void) detachChild:(CCNode *)child cleanup:(BOOL)doCleanup 387{ 388 // IMPORTANT: 389 // -1st do onExit 390 // -2nd cleanup 391 if (isRunning_) 392 [child onExit]; 393 394 // If you don't do cleanup, the child's actions will not get removed and the 395 // its scheduledSelectors_ dict will not get released! 396 if (doCleanup) 397 [child cleanup]; 398 399 // set parent nil at the end (issue #476) 400 [child setParent:nil]; 401 402 [children_ removeObject:child]; 403} 404 405// used internally to alter the zOrder variable. DON'T call this method manually 406-(void) _setZOrder:(int) z 407{ 408 zOrder_ = z; 409} 410 411// helper used by reorderChild & add 412-(void) insertChild:(CCNode*)child z:(int)z 413{ 414 int index=0; 415 BOOL added = NO; 416 CCNode *a; 417 CCARRAY_FOREACH(children_, a){ 418 if ( a.zOrder > z ) { 419 added = YES; 420 [ children_ insertObject:child atIndex:index]; 421 break; 422 } 423 index++; 424 } 425 426 if( ! added ) 427 [children_ addObject:child]; 428 429 [child _setZOrder:z]; 430} 431 432-(void) reorderChild:(CCNode*) child z:(int)z 433{ 434 NSAssert( child != nil, @"Child must be non-nil"); 435 436 [child retain]; 437 [children_ removeObject:child]; 438 439 [self insertChild:child z:z]; 440 441 [child release]; 442} 443 444#pragma mark CCNode Draw 445 446-(void) draw 447{ 448 // override me 449 // Only use this function to draw your staff. 450 // DON'T draw your stuff outside this method 451} 452 453-(void) visit 454{ 455 // quick return if not visible 456 if (!visible_) 457 return; 458 459 glPushMatrix(); 460 461 if ( grid_ && grid_.active) { 462 [grid_ beforeDraw]; 463 [self transformAncestors]; 464 } 465 466 [self transform]; 467 468 if(children_) { 469 ccArray *arrayData = children_->data; 470 unsigned int i=0; 471 472 // draw children zOrder < 0 473 for( ; i < arrayData->num; i++ ) { 474 CCNode *child = arrayData->arr[i]; 475 if ( [child zOrder] < 0 ) { 476 [child visit]; 477 } else 478 break; 479 } 480 481 // self draw 482 [self draw]; 483 484 // draw children zOrder >= 0 485 for( ; i < arrayData->num; i++ ) { 486 CCNode *child = arrayData->arr[i]; 487 [child visit]; 488 } 489 490 } else 491 [self draw]; 492 493 if ( grid_ && grid_.active) 494 [grid_ afterDraw:self]; 495 496 glPopMatrix(); 497} 498 499#pragma mark CCNode - Transformations 500 501-(void) transformAncestors 502{ 503 if( parent_ ) { 504 [parent_ transformAncestors]; 505 [parent_ transform]; 506 } 507} 508 509-(void) transform 510{ 511 // transformations 512 513#if CC_NODE_TRANSFORM_USING_AFFINE_MATRIX 514 // BEGIN alternative -- using cached transform 515 // 516 if( isTransformGLDirty_ ) { 517 CGAffineTransform t = [self nodeToParentTransform]; 518 CGAffineToGL(&t, transformGL_); 519 isTransformGLDirty_ = NO; 520 } 521 522 glMultMatrixf(transformGL_); 523 if( vertexZ_ ) 524 glTranslatef(0, 0, vertexZ_); 525 526 // XXX: Expensive calls. Camera should be integrated into the cached affine matrix 527 if ( camera_ && !(grid_ && grid_.active) ) { 528 BOOL translate = (anchorPointInPixels_.x != 0.0f || anchorPointInPixels_.y != 0.0f); 529 530 if( translate ) 531 glTranslatef(RENDER_IN_SUBPIXEL(anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(anchorPointInPixels_.y), 0); 532 533 [camera_ locate]; 534 535 if( translate ) 536 glTranslatef(RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0); 537 } 538 539 540 // END alternative 541 542#else 543 // BEGIN original implementation 544 // 545 // translate 546 if ( isRelativeAnchorPoint_ && (anchorPointInPixels_.x != 0 || anchorPointInPixels_.y != 0 ) ) 547 glTranslatef( RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0); 548 549 if (anchorPointInPixels_.x != 0 || anchorPointInPixels_.y != 0) 550 glTranslatef( RENDER_IN_SUBPIXEL(position_.x + anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(position_.y + anchorPointInPixels_.y), vertexZ_); 551 else if ( position_.x !=0 || position_.y !=0 || vertexZ_ != 0) 552 glTranslatef( RENDER_IN_SUBPIXEL(position_.x), RENDER_IN_SUBPIXEL(position_.y), vertexZ_ ); 553 554 // rotate 555 if (rotation_ != 0.0f ) 556 glRotatef( -rotation_, 0.0f, 0.0f, 1.0f ); 557 558 // scale 559 if (scaleX_ != 1.0f || scaleY_ != 1.0f) 560 glScalef( scaleX_, scaleY_, 1.0f ); 561 562 if ( camera_ && !(grid_ && grid_.active) ) 563 [camera_ locate]; 564 565 // restore and re-position point 566 if (anchorPointInPixels_.x != 0.0f || anchorPointInPixels_.y != 0.0f) 567 glTranslatef(RENDER_IN_SUBPIXEL(-anchorPointInPixels_.x), RENDER_IN_SUBPIXEL(-anchorPointInPixels_.y), 0); 568 569 // 570 // END original implementation 571#endif 572 573} 574 575#pragma mark CCNode SceneManagement 576 577-(void) onEnter 578{ 579 [children_ makeObjectsPerformSelector:@selector(onEnter)]; 580 581 [self resumeSchedulerAndActions]; 582 583 isRunning_ = YES; 584} 585 586-(void) onEnterTransitionDidFinish 587{ 588 [children_ makeObjectsPerformSelector:@selector(onEnterTransitionDidFinish)]; 589} 590 591-(void) onExit 592{ 593 [self pauseSchedulerAndActions]; 594 595 isRunning_ = NO; 596 597 [children_ makeObjectsPerformSelector:@selector(onExit)]; 598} 599 600#pragma mark CCNode Actions 601 602-(CCAction*) runAction:(CCAction*) action 603{ 604 NSAssert( action != nil, @"Argument must be non-nil"); 605 606 [[CCActionManager sharedManager] addAction:action target:self paused:!isRunning_]; 607 return action; 608} 609 610-(void) stopAllActions 611{ 612 [[CCActionManager sharedManager] removeAllActionsFromTarget:self]; 613} 614 615-(void) stopAction: (CCAction*) action 616{ 617 [[CCActionManager sharedManager] removeAction:action]; 618} 619 620-(void) stopActionByTag:(int)aTag 621{ 622 NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag"); 623 [[CCActionManager sharedManager] removeActionByTag:aTag target:self]; 624} 625 626-(CCAction*) getActionByTag:(int) aTag 627{ 628 NSAssert( aTag != kCCActionTagInvalid, @"Invalid tag"); 629 630 return [[CCActionManager sharedManager] getActionByTag:aTag target:self]; 631} 632 633-(int) numberOfRunningActions 634{ 635 return [[CCActionManager sharedManager] numberOfRunningActionsInTarget:self]; 636} 637 638 639#pragma mark CCNode - Callbacks 640 641-(void) scheduleUpdate 642{ 643 [self scheduleUpdateWithPriority:0]; 644} 645 646-(void) scheduleUpdateWithPriority:(int)priority 647{ 648 [[CCScheduler sharedScheduler] scheduleUpdateForTarget:self priority:priority paused:!isRunning_]; 649} 650 651-(void) unscheduleUpdate 652{ 653 [[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self]; 654} 655 656-(void) schedule:(SEL)selector 657{ 658 [self schedule:selector interval:0]; 659} 660 661-(void) schedule:(SEL)selector interval:(ccTime)interval 662{ 663 NSAssert( selector != nil, @"Argument must be non-nil"); 664 NSAssert( interval >=0, @"Arguemnt must be positive"); 665 666 [[CCScheduler sharedScheduler] scheduleSelector:selector forTarget:self interval:interval paused:!isRunning_]; 667} 668 669-(void) unschedule:(SEL)selector 670{ 671 // explicit nil handling 672 if (selector == nil) 673 return; 674 675 [[CCScheduler sharedScheduler] unscheduleSelector:selector forTarget:self]; 676} 677 678-(void) unscheduleAllSelectors 679{ 680 [[CCScheduler sharedScheduler] unscheduleAllSelectorsForTarget:self]; 681} 682- (void) resumeSchedulerAndActions 683{ 684 [[CCScheduler sharedScheduler] resumeTarget:self]; 685 [[CCActionManager sharedManager] resumeTarget:self]; 686} 687 688- (void) pauseSchedulerAndActions 689{ 690 [[CCScheduler sharedScheduler] pauseTarget:self]; 691 [[CCActionManager sharedManager] pauseTarget:self]; 692} 693 694#pragma mark CCNode Transform 695 696- (CGAffineTransform)nodeToParentTransform 697{ 698 if ( isTransformDirty_ ) { 699 700 transform_ = CGAffineTransformIdentity; 701 702 if ( !isRelativeAnchorPoint_ && !CGPointEqualToPoint(anchorPointInPixels_, CGPointZero) ) 703 transform_ = CGAffineTransformTranslate(transform_, anchorPointInPixels_.x, anchorPointInPixels_.y); 704 705 if( ! CGPointEqualToPoint(position_, CGPointZero) ) 706 transform_ = CGAffineTransformTranslate(transform_, position_.x, position_.y); 707 if( rotation_ != 0 ) 708 transform_ = CGAffineTransformRotate(transform_, -CC_DEGREES_TO_RADIANS(rotation_)); 709 if( ! (scaleX_ == 1 && scaleY_ == 1) ) 710 transform_ = CGAffineTransformScale(transform_, scaleX_, scaleY_); 711 712 if( ! CGPointEqualToPoint(anchorPointInPixels_, CGPointZero) ) 713 transform_ = CGAffineTransformTranslate(transform_, -anchorPointInPixels_.x, -anchorPointInPixels_.y); 714 715 isTransformDirty_ = NO; 716 } 717 718 return transform_; 719} 720 721- (CGAffineTransform)parentToNodeTransform 722{ 723 if ( isInverseDirty_ ) { 724 inverse_ = CGAffineTransformInvert([self nodeToParentTransform]); 725 isInverseDirty_ = NO; 726 } 727 728 return inverse_; 729} 730 731- (CGAffineTransform)nodeToWorldTransform 732{ 733 CGAffineTransform t = [self nodeToParentTransform]; 734 735 for (CCNode *p = parent_; p != nil; p = p.parent) 736 t = CGAffineTransformConcat(t, [p nodeToParentTransform]); 737 738 return t; 739} 740 741- (CGAffineTransform)worldToNodeTransform 742{ 743 return CGAffineTransformInvert([self nodeToWorldTransform]); 744} 745 746- (CGPoint)convertToNodeSpace:(CGPoint)worldPoint 747{ 748 return CGPointApplyAffineTransform(worldPoint, [self worldToNodeTransform]); 749} 750 751- (CGPoint)convertToWorldSpace:(CGPoint)nodePoint 752{ 753 return CGPointApplyAffineTransform(nodePoint, [self nodeToWorldTransform]); 754} 755 756- (CGPoint)convertToNodeSpaceAR:(CGPoint)worldPoint 757{ 758 CGPoint nodePoint = [self convertToNodeSpace:worldPoint]; 759 return ccpSub(nodePoint, anchorPointInPixels_); 760} 761 762- (CGPoint)convertToWorldSpaceAR:(CGPoint)nodePoint 763{ 764 nodePoint = ccpAdd(nodePoint, anchorPointInPixels_); 765 return [self convertToWorldSpace:nodePoint]; 766} 767 768- (CGPoint)convertToWindowSpace:(CGPoint)nodePoint 769{ 770 CGPoint worldPoint = [self convertToWorldSpace:nodePoint]; 771 return [[CCDirector sharedDirector] convertToUI:worldPoint]; 772} 773 774// convenience methods which take a UITouch instead of CGPoint 775 776- (CGPoint)convertTouchToNodeSpace:(UITouch *)touch 777{ 778 CGPoint point = [touch locationInView: [touch view]]; 779 point = [[CCDirector sharedDirector] convertToGL: point]; 780 return [self convertToNodeSpace:point]; 781} 782 783- (CGPoint)convertTouchToNodeSpaceAR:(UITouch *)touch 784{ 785 CGPoint point = [touch locationInView: [touch view]]; 786 point = [[CCDirector sharedDirector] convertToGL: point]; 787 return [self convertToNodeSpaceAR:point]; 788} 789 790@end