PageRenderTime 379ms CodeModel.GetById 26ms app.highlight 151ms RepoModel.GetById 2ms app.codeStats 0ms

/libs/cocos2d/CCIntervalAction.m

http://github.com/kstenerud/ObjectAL-for-iPhone
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