/libs/cocos2d/CCIntervalAction.m
Objective C | 1216 lines | 906 code | 193 blank | 117 comment | 52 complexity | 052a65f3e4833183d1634fc648525c8f 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 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 * 24 */ 25 26 27 28#import "CCIntervalAction.h" 29#import "CCSprite.h" 30#import "CCSpriteFrame.h" 31#import "CCNode.h" 32#import "Support/CGPointExtension.h" 33 34// 35// IntervalAction 36// 37#pragma mark - 38#pragma mark IntervalAction 39@implementation CCIntervalAction 40 41@synthesize elapsed; 42 43-(id) init 44{ 45 NSException* myException = [NSException 46 exceptionWithName:@"IntervalActionInit" 47 reason:@"Init not supported. Use InitWithDuration" 48 userInfo:nil]; 49 @throw myException; 50 51} 52 53+(id) actionWithDuration: (ccTime) d 54{ 55 return [[[self alloc] initWithDuration:d ] autorelease]; 56} 57 58-(id) initWithDuration: (ccTime) d 59{ 60 if( (self=[super init]) ) { 61 duration = d; 62 63 // prevent division by 0 64 // This comparison could be in step:, but it might decrease the performance 65 // by 3% in heavy based action games. 66 if( duration == 0 ) 67 duration = FLT_EPSILON; 68 elapsed = 0; 69 firstTick = YES; 70 } 71 return self; 72} 73 74-(id) copyWithZone: (NSZone*) zone 75{ 76 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] ]; 77 return copy; 78} 79 80 81- (BOOL) isDone 82{ 83 return (elapsed >= duration); 84} 85 86-(void) step: (ccTime) dt 87{ 88 if( firstTick ) { 89 firstTick = NO; 90 elapsed = 0; 91 } else 92 elapsed += dt; 93 94 [self update: MIN(1, elapsed/duration)]; 95} 96 97-(void) startWithTarget:(id)aTarget 98{ 99 [super startWithTarget:aTarget]; 100 elapsed = 0.0f; 101 firstTick = YES; 102} 103 104- (CCIntervalAction*) reverse 105{ 106 NSException* myException = [NSException 107 exceptionWithName:@"ReverseActionNotImplemented" 108 reason:@"Reverse Action not implemented" 109 userInfo:nil]; 110 @throw myException; 111} 112@end 113 114// 115// Sequence 116// 117#pragma mark - 118#pragma mark Sequence 119@implementation CCSequence 120+(id) actionOne: (CCFiniteTimeAction*) one two: (CCFiniteTimeAction*) two 121{ 122 return [[[self alloc] initOne:one two:two ] autorelease]; 123} 124 125+(id) actions: (CCFiniteTimeAction*) action1, ... 126{ 127 va_list params; 128 va_start(params,action1); 129 130 CCFiniteTimeAction *now; 131 CCFiniteTimeAction *prev = action1; 132 133 while( action1 ) { 134 now = va_arg(params,CCFiniteTimeAction*); 135 if ( now ) 136 prev = [self actionOne: prev two: now]; 137 else 138 break; 139 } 140 va_end(params); 141 return prev; 142} 143 144-(id) initOne: (CCFiniteTimeAction*) one_ two: (CCFiniteTimeAction*) two_ 145{ 146 NSAssert( one_!=nil, @"Sequence: argument one must be non-nil"); 147 NSAssert( two_!=nil, @"Sequence: argument two must be non-nil"); 148 149 CCFiniteTimeAction *one = one_; 150 CCFiniteTimeAction *two = two_; 151 152 ccTime d = [one duration] + [two duration]; 153 [super initWithDuration: d]; 154 155 actions[0] = [one retain]; 156 actions[1] = [two retain]; 157 158 return self; 159} 160 161-(id) copyWithZone: (NSZone*) zone 162{ 163 CCAction *copy = [[[self class] allocWithZone:zone] initOne:[[actions[0] copy] autorelease] two:[[actions[1] copy] autorelease] ]; 164 return copy; 165} 166 167-(void) dealloc 168{ 169 [actions[0] release]; 170 [actions[1] release]; 171 [super dealloc]; 172} 173 174-(void) startWithTarget:(id)aTarget 175{ 176 [super startWithTarget:aTarget]; 177 split = [actions[0] duration] / duration; 178 last = -1; 179} 180 181-(void) stop 182{ 183 [actions[0] stop]; 184 [actions[1] stop]; 185 [super stop]; 186} 187 188-(void) update: (ccTime) t 189{ 190 int found = 0; 191 ccTime new_t = 0.0f; 192 193 if( t >= split ) { 194 found = 1; 195 if ( split == 1 ) 196 new_t = 1; 197 else 198 new_t = (t-split) / (1 - split ); 199 } else { 200 found = 0; 201 if( split != 0 ) 202 new_t = t / split; 203 else 204 new_t = 1; 205 } 206 207 if (last == -1 && found==1) { 208 [actions[0] startWithTarget:target]; 209 [actions[0] update:1.0f]; 210 [actions[0] stop]; 211 } 212 213 if (last != found ) { 214 if( last != -1 ) { 215 [actions[last] update: 1.0f]; 216 [actions[last] stop]; 217 } 218 [actions[found] startWithTarget:target]; 219 } 220 [actions[found] update: new_t]; 221 last = found; 222} 223 224- (CCIntervalAction *) reverse 225{ 226 return [[self class] actionOne: [actions[1] reverse] two: [actions[0] reverse ] ]; 227} 228@end 229 230// 231// Repeat 232// 233#pragma mark - 234#pragma mark CCRepeat 235@implementation CCRepeat 236+(id) actionWithAction:(CCFiniteTimeAction*)action times:(unsigned int)times 237{ 238 return [[[self alloc] initWithAction:action times:times] autorelease]; 239} 240 241-(id) initWithAction:(CCFiniteTimeAction*)action times:(unsigned int)times 242{ 243 ccTime d = [action duration] * times; 244 245 if( (self=[super initWithDuration: d ]) ) { 246 times_ = times; 247 other_ = [action retain]; 248 249 total_ = 0; 250 } 251 return self; 252} 253 254-(id) copyWithZone: (NSZone*) zone 255{ 256 CCAction *copy = [[[self class] allocWithZone:zone] initWithAction:[[other_ copy] autorelease] times:times_]; 257 return copy; 258} 259 260-(void) dealloc 261{ 262 [other_ release]; 263 [super dealloc]; 264} 265 266-(void) startWithTarget:(id)aTarget 267{ 268 total_ = 0; 269 [super startWithTarget:aTarget]; 270 [other_ startWithTarget:aTarget]; 271} 272 273-(void) stop 274{ 275 [other_ stop]; 276 [super stop]; 277} 278 279 280// issue #80. Instead of hooking step:, hook update: since it can be called by any 281// container action like Repeat, Sequence, AccelDeccel, etc.. 282-(void) update:(ccTime) dt 283{ 284 ccTime t = dt * times_; 285 if( t > total_+1 ) { 286 [other_ update:1.0f]; 287 total_++; 288 [other_ stop]; 289 [other_ startWithTarget:target]; 290 291 // repeat is over ? 292 if( total_== times_ ) 293 // so, set it in the original position 294 [other_ update:0]; 295 else { 296 // no ? start next repeat with the right update 297 // to prevent jerk (issue #390) 298 [other_ update: t-total_]; 299 } 300 301 } else { 302 303 float r = fmodf(t, 1.0f); 304 305 // fix last repeat position 306 // else it could be 0. 307 if( dt== 1.0f) { 308 r=1.0f; 309 total_++; // this is the added line 310 } 311 [other_ update: MIN(r,1)]; 312 } 313} 314 315-(BOOL) isDone 316{ 317 return ( total_ == times_ ); 318} 319 320- (CCIntervalAction *) reverse 321{ 322 return [[self class] actionWithAction:[other_ reverse] times:times_]; 323} 324@end 325 326// 327// Spawn 328// 329#pragma mark - 330#pragma mark Spawn 331 332@implementation CCSpawn 333+(id) actions: (CCFiniteTimeAction*) action1, ... 334{ 335 va_list params; 336 va_start(params,action1); 337 338 CCFiniteTimeAction *now; 339 CCFiniteTimeAction *prev = action1; 340 341 while( action1 ) { 342 now = va_arg(params,CCFiniteTimeAction*); 343 if ( now ) 344 prev = [self actionOne: prev two: now]; 345 else 346 break; 347 } 348 va_end(params); 349 return prev; 350} 351 352+(id) actionOne: (CCFiniteTimeAction*) one two: (CCFiniteTimeAction*) two 353{ 354 return [[[self alloc] initOne:one two:two ] autorelease]; 355} 356 357-(id) initOne: (CCFiniteTimeAction*) one_ two: (CCFiniteTimeAction*) two_ 358{ 359 NSAssert( one_!=nil, @"Spawn: argument one must be non-nil"); 360 NSAssert( two_!=nil, @"Spawn: argument two must be non-nil"); 361 362 ccTime d1 = [one_ duration]; 363 ccTime d2 = [two_ duration]; 364 365 [super initWithDuration: fmaxf(d1,d2)]; 366 367 one = one_; 368 two = two_; 369 370 if( d1 > d2 ) 371 two = [CCSequence actionOne: two_ two:[CCDelayTime actionWithDuration: (d1-d2)] ]; 372 else if( d1 < d2) 373 one = [CCSequence actionOne: one_ two: [CCDelayTime actionWithDuration: (d2-d1)] ]; 374 375 [one retain]; 376 [two retain]; 377 return self; 378} 379 380-(id) copyWithZone: (NSZone*) zone 381{ 382 CCAction *copy = [[[self class] allocWithZone: zone] initOne: [[one copy] autorelease] two: [[two copy] autorelease] ]; 383 return copy; 384} 385 386-(void) dealloc 387{ 388 [one release]; 389 [two release]; 390 [super dealloc]; 391} 392 393-(void) startWithTarget:(id)aTarget 394{ 395 [super startWithTarget:aTarget]; 396 [one startWithTarget:target]; 397 [two startWithTarget:target]; 398} 399 400-(void) stop 401{ 402 [one stop]; 403 [two stop]; 404 [super stop]; 405} 406 407-(void) update: (ccTime) t 408{ 409 [one update:t]; 410 [two update:t]; 411} 412 413- (CCIntervalAction *) reverse 414{ 415 return [[self class] actionOne: [one reverse] two: [two reverse ] ]; 416} 417@end 418 419// 420// RotateTo 421// 422#pragma mark - 423#pragma mark RotateTo 424 425@implementation CCRotateTo 426+(id) actionWithDuration: (ccTime) t angle:(float) a 427{ 428 return [[[self alloc] initWithDuration:t angle:a ] autorelease]; 429} 430 431-(id) initWithDuration: (ccTime) t angle:(float) a 432{ 433 if( (self=[super initWithDuration: t]) ) { 434 dstAngle = a; 435 } 436 return self; 437} 438 439-(id) copyWithZone: (NSZone*) zone 440{ 441 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration:[self duration] angle: dstAngle]; 442 return copy; 443} 444 445-(void) startWithTarget:(CCNode *)aTarget 446{ 447 [super startWithTarget:aTarget]; 448 449 startAngle = [target rotation]; 450 if (startAngle > 0) 451 startAngle = fmodf(startAngle, 360.0f); 452 else 453 startAngle = fmodf(startAngle, -360.0f); 454 455 diffAngle = dstAngle - startAngle; 456 if (diffAngle > 180) 457 diffAngle -= 360; 458 if (diffAngle < -180) 459 diffAngle += 360; 460} 461-(void) update: (ccTime) t 462{ 463 [target setRotation: startAngle + diffAngle * t]; 464} 465@end 466 467 468// 469// RotateBy 470// 471#pragma mark - 472#pragma mark RotateBy 473 474@implementation CCRotateBy 475+(id) actionWithDuration: (ccTime) t angle:(float) a 476{ 477 return [[[self alloc] initWithDuration:t angle:a ] autorelease]; 478} 479 480-(id) initWithDuration: (ccTime) t angle:(float) a 481{ 482 if( (self=[super initWithDuration: t]) ) { 483 angle = a; 484 } 485 return self; 486} 487 488-(id) copyWithZone: (NSZone*) zone 489{ 490 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] angle: angle]; 491 return copy; 492} 493 494-(void) startWithTarget:(id)aTarget 495{ 496 [super startWithTarget:aTarget]; 497 startAngle = [target rotation]; 498} 499 500-(void) update: (ccTime) t 501{ 502 // XXX: shall I add % 360 503 [target setRotation: (startAngle + angle * t )]; 504} 505 506-(CCIntervalAction*) reverse 507{ 508 return [[self class] actionWithDuration: duration angle: -angle]; 509} 510 511@end 512 513// 514// MoveTo 515// 516#pragma mark - 517#pragma mark MoveTo 518 519@implementation CCMoveTo 520+(id) actionWithDuration: (ccTime) t position: (CGPoint) p 521{ 522 return [[[self alloc] initWithDuration:t position:p ] autorelease]; 523} 524 525-(id) initWithDuration: (ccTime) t position: (CGPoint) p 526{ 527 if( (self=[super initWithDuration: t]) ) { 528 endPosition = p; 529 } 530 return self; 531} 532 533-(id) copyWithZone: (NSZone*) zone 534{ 535 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] position: endPosition]; 536 return copy; 537} 538 539-(void) startWithTarget:(CCNode *)aTarget 540{ 541 [super startWithTarget:aTarget]; 542 startPosition = [(CCNode*)target position]; 543 delta = ccpSub( endPosition, startPosition ); 544} 545 546-(void) update: (ccTime) t 547{ 548 [target setPosition: ccp( (startPosition.x + delta.x * t ), (startPosition.y + delta.y * t ) )]; 549} 550@end 551 552// 553// MoveBy 554// 555#pragma mark - 556#pragma mark MoveBy 557 558@implementation CCMoveBy 559+(id) actionWithDuration: (ccTime) t position: (CGPoint) p 560{ 561 return [[[self alloc] initWithDuration:t position:p ] autorelease]; 562} 563 564-(id) initWithDuration: (ccTime) t position: (CGPoint) p 565{ 566 if( (self=[super initWithDuration: t]) ) { 567 delta = p; 568 } 569 return self; 570} 571 572-(id) copyWithZone: (NSZone*) zone 573{ 574 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] position: delta]; 575 return copy; 576} 577 578-(void) startWithTarget:(CCNode *)aTarget 579{ 580 CGPoint dTmp = delta; 581 [super startWithTarget:aTarget]; 582 delta = dTmp; 583} 584 585-(CCIntervalAction*) reverse 586{ 587 return [[self class] actionWithDuration: duration position: ccp( -delta.x, -delta.y)]; 588} 589@end 590 591// 592// JumpBy 593// 594#pragma mark - 595#pragma mark JumpBy 596 597@implementation CCJumpBy 598+(id) actionWithDuration: (ccTime) t position: (CGPoint) pos height: (ccTime) h jumps:(int)j 599{ 600 return [[[self alloc] initWithDuration: t position: pos height: h jumps:j] autorelease]; 601} 602 603-(id) initWithDuration: (ccTime) t position: (CGPoint) pos height: (ccTime) h jumps:(int)j 604{ 605 if( (self=[super initWithDuration:t]) ) { 606 delta = pos; 607 height = h; 608 jumps = j; 609 } 610 return self; 611} 612 613-(id) copyWithZone: (NSZone*) zone 614{ 615 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] position: delta height:height jumps:jumps]; 616 return copy; 617} 618 619-(void) startWithTarget:(id)aTarget 620{ 621 [super startWithTarget:aTarget]; 622 startPosition = [(CCNode*)target position]; 623} 624 625-(void) update: (ccTime) t 626{ 627 // Sin jump. Less realistic 628// ccTime y = height * fabsf( sinf(t * (CGFloat)M_PI * jumps ) ); 629// y += delta.y * t; 630// ccTime x = delta.x * t; 631// [target setPosition: ccp( startPosition.x + x, startPosition.y + y )]; 632 633 // parabolic jump (since v0.8.2) 634 ccTime frac = fmodf( t * jumps, 1.0f ); 635 ccTime y = height * 4 * frac * (1 - frac); 636 y += delta.y * t; 637 ccTime x = delta.x * t; 638 [target setPosition: ccp( startPosition.x + x, startPosition.y + y )]; 639 640} 641 642-(CCIntervalAction*) reverse 643{ 644 return [[self class] actionWithDuration: duration position: ccp(-delta.x,-delta.y) height: height jumps:jumps]; 645} 646@end 647 648// 649// JumpTo 650// 651#pragma mark - 652#pragma mark JumpTo 653 654@implementation CCJumpTo 655-(void) startWithTarget:(CCNode *)aTarget 656{ 657 [super startWithTarget:aTarget]; 658 delta = ccp( delta.x - startPosition.x, delta.y - startPosition.y ); 659} 660@end 661 662 663#pragma mark - 664#pragma mark BezierBy 665 666// Bezier cubic formula: 667// ((1 - t) + t)3 = 1 668// Expands to… 669// (1 - t)3 + 3t(1-t)2 + 3t2(1 - t) + t3 = 1 670static inline float bezierat( float a, float b, float c, float d, ccTime t ) 671{ 672 return (powf(1-t,3) * a + 673 3*t*(powf(1-t,2))*b + 674 3*powf(t,2)*(1-t)*c + 675 powf(t,3)*d ); 676} 677 678// 679// BezierBy 680// 681@implementation CCBezierBy 682+(id) actionWithDuration: (ccTime) t bezier:(ccBezierConfig) c 683{ 684 return [[[self alloc] initWithDuration:t bezier:c ] autorelease]; 685} 686 687-(id) initWithDuration: (ccTime) t bezier:(ccBezierConfig) c 688{ 689 if( (self=[super initWithDuration: t]) ) { 690 config = c; 691 } 692 return self; 693} 694 695-(id) copyWithZone: (NSZone*) zone 696{ 697 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] bezier: config]; 698 return copy; 699} 700 701-(void) startWithTarget:(id)aTarget 702{ 703 [super startWithTarget:aTarget]; 704 startPosition = [(CCNode*)target position]; 705} 706 707-(void) update: (ccTime) t 708{ 709 float xa = 0; 710 float xb = config.controlPoint_1.x; 711 float xc = config.controlPoint_2.x; 712 float xd = config.endPosition.x; 713 714 float ya = 0; 715 float yb = config.controlPoint_1.y; 716 float yc = config.controlPoint_2.y; 717 float yd = config.endPosition.y; 718 719 float x = bezierat(xa, xb, xc, xd, t); 720 float y = bezierat(ya, yb, yc, yd, t); 721 [target setPosition: ccpAdd( startPosition, ccp(x,y))]; 722} 723 724- (CCIntervalAction*) reverse 725{ 726 ccBezierConfig r; 727 728 r.endPosition = ccpNeg(config.endPosition); 729 r.controlPoint_1 = ccpAdd(config.controlPoint_2, ccpNeg(config.endPosition)); 730 r.controlPoint_2 = ccpAdd(config.controlPoint_1, ccpNeg(config.endPosition)); 731 732 CCBezierBy *action = [[self class] actionWithDuration:[self duration] bezier:r]; 733 return action; 734} 735@end 736 737// 738// BezierTo 739// 740#pragma mark - 741#pragma mark BezierTo 742@implementation CCBezierTo 743-(void) startWithTarget:(id)aTarget 744{ 745 [super startWithTarget:aTarget]; 746 config.controlPoint_1 = ccpSub(config.controlPoint_1, startPosition); 747 config.controlPoint_2 = ccpSub(config.controlPoint_2, startPosition); 748 config.endPosition = ccpSub(config.endPosition, startPosition); 749} 750@end 751 752 753// 754// ScaleTo 755// 756#pragma mark - 757#pragma mark ScaleTo 758@implementation CCScaleTo 759+(id) actionWithDuration: (ccTime) t scale:(float) s 760{ 761 return [[[self alloc] initWithDuration: t scale:s] autorelease]; 762} 763 764-(id) initWithDuration: (ccTime) t scale:(float) s 765{ 766 if( (self=[super initWithDuration: t]) ) { 767 endScaleX = s; 768 endScaleY = s; 769 } 770 return self; 771} 772 773+(id) actionWithDuration: (ccTime) t scaleX:(float)sx scaleY:(float)sy 774{ 775 return [[[self alloc] initWithDuration: t scaleX:sx scaleY:sy] autorelease]; 776} 777 778-(id) initWithDuration: (ccTime) t scaleX:(float)sx scaleY:(float)sy 779{ 780 if( (self=[super initWithDuration: t]) ) { 781 endScaleX = sx; 782 endScaleY = sy; 783 } 784 return self; 785} 786 787-(id) copyWithZone: (NSZone*) zone 788{ 789 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] scaleX:endScaleX scaleY:endScaleY]; 790 return copy; 791} 792 793-(void) startWithTarget:(CCNode *)aTarget 794{ 795 [super startWithTarget:aTarget]; 796 startScaleX = [target scaleX]; 797 startScaleY = [target scaleY]; 798 deltaX = endScaleX - startScaleX; 799 deltaY = endScaleY - startScaleY; 800} 801 802-(void) update: (ccTime) t 803{ 804 [target setScaleX: (startScaleX + deltaX * t ) ]; 805 [target setScaleY: (startScaleY + deltaY * t ) ]; 806} 807@end 808 809// 810// ScaleBy 811// 812#pragma mark - 813#pragma mark ScaleBy 814@implementation CCScaleBy 815-(void) startWithTarget:(CCNode *)aTarget 816{ 817 [super startWithTarget:aTarget]; 818 deltaX = startScaleX * endScaleX - startScaleX; 819 deltaY = startScaleY * endScaleY - startScaleY; 820} 821 822-(CCIntervalAction*) reverse 823{ 824 return [[self class] actionWithDuration: duration scaleX: 1/endScaleX scaleY:1/endScaleY]; 825} 826@end 827 828// 829// Blink 830// 831#pragma mark - 832#pragma mark Blink 833@implementation CCBlink 834+(id) actionWithDuration: (ccTime) t blinks: (unsigned int) b 835{ 836 return [[[ self alloc] initWithDuration: t blinks: b] autorelease]; 837} 838 839-(id) initWithDuration: (ccTime) t blinks: (unsigned int) b 840{ 841 if( (self=[super initWithDuration: t] ) ) { 842 times = b; 843 } 844 return self; 845} 846 847-(id) copyWithZone: (NSZone*) zone 848{ 849 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] blinks: times]; 850 return copy; 851} 852 853-(void) update: (ccTime) t 854{ 855 ccTime slice = 1.0f / times; 856 ccTime m = fmodf(t, slice); 857 [target setVisible: (m > slice/2) ? YES : NO]; 858} 859 860-(CCIntervalAction*) reverse 861{ 862 // return 'self' 863 return [[self class] actionWithDuration: duration blinks: times]; 864} 865@end 866 867// 868// FadeIn 869// 870#pragma mark - 871#pragma mark FadeIn 872@implementation CCFadeIn 873-(void) update: (ccTime) t 874{ 875 [(id<CCRGBAProtocol>) target setOpacity: 255 *t]; 876} 877-(CCIntervalAction*) reverse 878{ 879 return [CCFadeOut actionWithDuration: duration]; 880} 881@end 882 883// 884// FadeOut 885// 886#pragma mark - 887#pragma mark FadeOut 888@implementation CCFadeOut 889-(void) update: (ccTime) t 890{ 891 [(id<CCRGBAProtocol>) target setOpacity: 255 *(1-t)]; 892} 893-(CCIntervalAction*) reverse 894{ 895 return [CCFadeIn actionWithDuration: duration]; 896} 897@end 898 899// 900// FadeTo 901// 902#pragma mark - 903#pragma mark FadeTo 904@implementation CCFadeTo 905+(id) actionWithDuration: (ccTime) t opacity: (GLubyte) o 906{ 907 return [[[ self alloc] initWithDuration: t opacity: o] autorelease]; 908} 909 910-(id) initWithDuration: (ccTime) t opacity: (GLubyte) o 911{ 912 if( (self=[super initWithDuration: t] ) ) 913 toOpacity = o; 914 return self; 915} 916 917-(id) copyWithZone: (NSZone*) zone 918{ 919 CCAction *copy = [[[self class] allocWithZone: zone] initWithDuration: [self duration] opacity: toOpacity]; 920 return copy; 921} 922 923-(void) startWithTarget:(CCNode *)aTarget 924{ 925 [super startWithTarget:aTarget]; 926 fromOpacity = [(id<CCRGBAProtocol>)target opacity]; 927} 928 929-(void) update: (ccTime) t 930{ 931 [(id<CCRGBAProtocol>)target setOpacity: fromOpacity + ( toOpacity - fromOpacity ) * t]; 932} 933@end 934 935// 936// TintTo 937// 938#pragma mark - 939#pragma mark TintTo 940@implementation CCTintTo 941+(id) actionWithDuration:(ccTime)t red:(GLubyte)r green:(GLubyte)g blue:(GLubyte)b 942{ 943 return [[(CCTintTo*)[ self alloc] initWithDuration:t red:r green:g blue:b] autorelease]; 944} 945 946-(id) initWithDuration: (ccTime) t red:(GLubyte)r green:(GLubyte)g blue:(GLubyte)b 947{ 948 if( (self=[super initWithDuration: t] ) ) { 949 to = ccc3(r,g,b); 950 } 951 return self; 952} 953 954-(id) copyWithZone: (NSZone*) zone 955{ 956 CCAction *copy = [(CCTintTo*)[[self class] allocWithZone: zone] initWithDuration: [self duration] red:to.r green:to.g blue:to.b]; 957 return copy; 958} 959 960-(void) startWithTarget:(id)aTarget 961{ 962 [super startWithTarget:aTarget]; 963 964 id<CCRGBAProtocol> tn = (id<CCRGBAProtocol>) target; 965 from = [tn color]; 966} 967 968-(void) update: (ccTime) t 969{ 970 id<CCRGBAProtocol> tn = (id<CCRGBAProtocol>) target; 971 [tn setColor:ccc3(from.r + (to.r - from.r) * t, from.g + (to.g - from.g) * t, from.b + (to.b - from.b) * t)]; 972} 973@end 974 975// 976// TintBy 977// 978#pragma mark - 979#pragma mark TintBy 980@implementation CCTintBy 981+(id) actionWithDuration:(ccTime)t red:(GLshort)r green:(GLshort)g blue:(GLshort)b 982{ 983 return [[(CCTintBy*)[ self alloc] initWithDuration:t red:r green:g blue:b] autorelease]; 984} 985 986-(id) initWithDuration:(ccTime)t red:(GLshort)r green:(GLshort)g blue:(GLshort)b 987{ 988 if( (self=[super initWithDuration: t] ) ) { 989 deltaR = r; 990 deltaG = g; 991 deltaB = b; 992 } 993 return self; 994} 995 996-(id) copyWithZone: (NSZone*) zone 997{ 998 return[(CCTintBy*)[[self class] allocWithZone: zone] initWithDuration: [self duration] red:deltaR green:deltaG blue:deltaB]; 999} 1000 1001-(void) startWithTarget:(id)aTarget 1002{ 1003 [super startWithTarget:aTarget]; 1004 1005 id<CCRGBAProtocol> tn = (id<CCRGBAProtocol>) target; 1006 ccColor3B color = [tn color]; 1007 fromR = color.r; 1008 fromG = color.g; 1009 fromB = color.b; 1010} 1011 1012-(void) update: (ccTime) t 1013{ 1014 id<CCRGBAProtocol> tn = (id<CCRGBAProtocol>) target; 1015 [tn setColor:ccc3( fromR + deltaR * t, fromG + deltaG * t, fromB + deltaB * t)]; 1016} 1017- (CCIntervalAction*) reverse 1018{ 1019 return [CCTintBy actionWithDuration:duration red:-deltaR green:-deltaG blue:-deltaB]; 1020} 1021@end 1022 1023// 1024// DelayTime 1025// 1026#pragma mark - 1027#pragma mark DelayTime 1028@implementation CCDelayTime 1029-(void) update: (ccTime) t 1030{ 1031 return; 1032} 1033 1034-(id)reverse 1035{ 1036 return [[self class] actionWithDuration:duration]; 1037} 1038@end 1039 1040// 1041// ReverseTime 1042// 1043#pragma mark - 1044#pragma mark ReverseTime 1045@implementation CCReverseTime 1046+(id) actionWithAction: (CCFiniteTimeAction*) action 1047{ 1048 // casting to prevent warnings 1049 CCReverseTime *a = [super alloc]; 1050 return [[a initWithAction:action] autorelease]; 1051} 1052 1053-(id) initWithAction: (CCFiniteTimeAction*) action 1054{ 1055 if( (self=[super initWithDuration: [action duration]]) ) { 1056 1057 other = [action retain]; 1058 } 1059 return self; 1060} 1061 1062-(id) copyWithZone: (NSZone*) zone 1063{ 1064 return [[[self class] allocWithZone: zone] initWithAction:[[other copy] autorelease] ]; 1065} 1066 1067-(void) dealloc 1068{ 1069 [other release]; 1070 [super dealloc]; 1071} 1072 1073-(void) startWithTarget:(id)aTarget 1074{ 1075 [super startWithTarget:aTarget]; 1076 [other startWithTarget:target]; 1077} 1078 1079-(void) stop 1080{ 1081 [other stop]; 1082 [super stop]; 1083} 1084 1085-(void) update:(ccTime)t 1086{ 1087 [other update:1-t]; 1088} 1089 1090-(CCIntervalAction*) reverse 1091{ 1092 return [[other copy] autorelease]; 1093} 1094@end 1095 1096// 1097// Animate 1098// 1099 1100#pragma mark - 1101#pragma mark Animate 1102@implementation CCAnimate 1103 1104@synthesize animation = animation_; 1105 1106+(id) actionWithAnimation: (CCAnimation*)anim 1107{ 1108 return [[[self alloc] initWithAnimation:anim restoreOriginalFrame:YES] autorelease]; 1109} 1110 1111+(id) actionWithAnimation: (CCAnimation*)anim restoreOriginalFrame:(BOOL)b 1112{ 1113 return [[[self alloc] initWithAnimation:anim restoreOriginalFrame:b] autorelease]; 1114} 1115 1116+(id) actionWithDuration:(ccTime)duration animation: (CCAnimation*)anim restoreOriginalFrame:(BOOL)b 1117{ 1118 return [[[self alloc] initWithDuration:duration animation:anim restoreOriginalFrame:b] autorelease]; 1119} 1120 1121-(id) initWithAnimation: (CCAnimation*)anim 1122{ 1123 NSAssert( anim!=nil, @"Animate: argument Animation must be non-nil"); 1124 return [self initWithAnimation:anim restoreOriginalFrame:YES]; 1125} 1126 1127-(id) initWithAnimation: (CCAnimation*)anim restoreOriginalFrame:(BOOL) b 1128{ 1129 NSAssert( anim!=nil, @"Animate: argument Animation must be non-nil"); 1130 1131 if( (self=[super initWithDuration: [[anim frames] count] * [anim delay]]) ) { 1132 1133 restoreOriginalFrame = b; 1134 self.animation = anim; 1135 origFrame = nil; 1136 } 1137 return self; 1138} 1139 1140-(id) initWithDuration:(ccTime)aDuration animation: (CCAnimation*)anim restoreOriginalFrame:(BOOL) b 1141{ 1142 NSAssert( anim!=nil, @"Animate: argument Animation must be non-nil"); 1143 1144 if( (self=[super initWithDuration:aDuration] ) ) { 1145 1146 restoreOriginalFrame = b; 1147 self.animation = anim; 1148 origFrame = nil; 1149 } 1150 return self; 1151} 1152 1153 1154-(id) copyWithZone: (NSZone*) zone 1155{ 1156 return [[[self class] allocWithZone: zone] initWithDuration:duration animation:animation_ restoreOriginalFrame:restoreOriginalFrame]; 1157} 1158 1159-(void) dealloc 1160{ 1161 [animation_ release]; 1162 [origFrame release]; 1163 [super dealloc]; 1164} 1165 1166-(void) startWithTarget:(id)aTarget 1167{ 1168 [super startWithTarget:aTarget]; 1169 CCSprite *sprite = target; 1170 1171 [origFrame release]; 1172 1173 if( restoreOriginalFrame ) 1174 origFrame = [[sprite displayedFrame] retain]; 1175} 1176 1177-(void) stop 1178{ 1179 if( restoreOriginalFrame ) { 1180 CCSprite *sprite = target; 1181 [sprite setDisplayFrame:origFrame]; 1182 } 1183 1184 [super stop]; 1185} 1186 1187-(void) update: (ccTime) t 1188{ 1189 NSArray *frames = [animation_ frames]; 1190 NSUInteger numberOfFrames = [frames count]; 1191 1192 NSUInteger idx = t * numberOfFrames; 1193 1194 if( idx >= numberOfFrames ) { 1195 idx = numberOfFrames -1; 1196 } 1197 CCSprite *sprite = target; 1198 if (! [sprite isFrameDisplayed: [frames objectAtIndex: idx]] ) { 1199 [sprite setDisplayFrame: [frames objectAtIndex:idx]]; 1200 } 1201} 1202 1203- (CCIntervalAction *) reverse 1204{ 1205 NSArray *oldArray = [animation_ frames]; 1206 NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:[oldArray count]]; 1207 NSEnumerator *enumerator = [oldArray reverseObjectEnumerator]; 1208 for (id element in enumerator) { 1209 [newArray addObject:[[element copy] autorelease]]; 1210 } 1211 1212 CCAnimation *newAnim = [CCAnimation animationWithName:animation_.name delay:animation_.delay frames:newArray]; 1213 return [[self class] actionWithDuration:duration animation:newAnim restoreOriginalFrame:restoreOriginalFrame]; 1214} 1215 1216@end