/*
* cocos2d for iPhone: http://www.cocos2d-iphone.org
*
* Copyright (c) 2009 On-Core
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#import "CCActionTiledGrid.h"
#import "CCDirector.h"
#import "ccMacros.h"
#import "Support/CGPointExtension.h"
typedef struct
{
CGPoint position;
CGPoint startPosition;
ccGridSize delta;
} Tile;
#pragma mark -
#pragma mark ShakyTiles3D
@implementation CCShakyTiles3D
+(id)actionWithRange:(int)range shakeZ:(BOOL)shakeZ grid:(ccGridSize)gridSize duration:(ccTime)d
{
return [[[self alloc] initWithRange:range shakeZ:shakeZ grid:gridSize duration:d] autorelease];
}
-(id)initWithRange:(int)range shakeZ:(BOOL)sz grid:(ccGridSize)gSize duration:(ccTime)d
{
if ( (self = [super initWithSize:gSize duration:d]) )
{
randrange = range;
shakeZ = sz;
}
return self;
}
-(id) copyWithZone: (NSZone*) zone
{
CCGridAction *copy = [[[self class] allocWithZone:zone] initWithRange:randrange shakeZ:shakeZ grid:gridSize_ duration:duration_];
return copy;
}
-(void)update:(ccTime)time
{
int i, j;
for( i = 0; i < gridSize_.x; i++ )
{
for( j = 0; j < gridSize_.y; j++ )
{
ccQuad3 coords = [self originalTile:ccg(i,j)];
// X
coords.bl.x += ( rand() % (randrange*2) ) - randrange;
coords.br.x += ( rand() % (randrange*2) ) - randrange;
coords.tl.x += ( rand() % (randrange*2) ) - randrange;
coords.tr.x += ( rand() % (randrange*2) ) - randrange;
// Y
coords.bl.y += ( rand() % (randrange*2) ) - randrange;
coords.br.y += ( rand() % (randrange*2) ) - randrange;
coords.tl.y += ( rand() % (randrange*2) ) - randrange;
coords.tr.y += ( rand() % (randrange*2) ) - randrange;
if( shakeZ ) {
coords.bl.z += ( rand() % (randrange*2) ) - randrange;
coords.br.z += ( rand() % (randrange*2) ) - randrange;
coords.tl.z += ( rand() % (randrange*2) ) - randrange;
coords.tr.z += ( rand() % (randrange*2) ) - randrange;
}
[self setTile:ccg(i,j) coords:coords];
}
}
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark CCShatteredTiles3D
@implementation CCShatteredTiles3D
+(id)actionWithRange:(int)range shatterZ:(BOOL)sz grid:(ccGridSize)gridSize duration:(ccTime)d
{
return [[[self alloc] initWithRange:range shatterZ:sz grid:gridSize duration:d] autorelease];
}
-(id)initWithRange:(int)range shatterZ:(BOOL)sz grid:(ccGridSize)gSize duration:(ccTime)d
{
if ( (self = [super initWithSize:gSize duration:d]) )
{
once = NO;
randrange = range;
shatterZ = sz;
}
return self;
}
-(id) copyWithZone: (NSZone*) zone
{
CCGridAction *copy = [[[self class] allocWithZone:zone] initWithRange:randrange shatterZ:shatterZ grid:gridSize_ duration:duration_];
return copy;
}
-(void)update:(ccTime)time
{
int i, j;
if ( once == NO )
{
for( i = 0; i < gridSize_.x; i++ )
{
for( j = 0; j < gridSize_.y; j++ )
{
ccQuad3 coords = [self originalTile:ccg(i,j)];
// X
coords.bl.x += ( rand() % (randrange*2) ) - randrange;
coords.br.x += ( rand() % (randrange*2) ) - randrange;
coords.tl.x += ( rand() % (randrange*2) ) - randrange;
coords.tr.x += ( rand() % (randrange*2) ) - randrange;
// Y
coords.bl.y += ( rand() % (randrange*2) ) - randrange;
coords.br.y += ( rand() % (randrange*2) ) - randrange;
coords.tl.y += ( rand() % (randrange*2) ) - randrange;
coords.tr.y += ( rand() % (randrange*2) ) - randrange;
if( shatterZ ) {
coords.bl.z += ( rand() % (randrange*2) ) - randrange;
coords.br.z += ( rand() % (randrange*2) ) - randrange;
coords.tl.z += ( rand() % (randrange*2) ) - randrange;
coords.tr.z += ( rand() % (randrange*2) ) - randrange;
}
[self setTile:ccg(i,j) coords:coords];
}
}
once = YES;
}
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark CCShuffleTiles
@implementation CCShuffleTiles
+(id)actionWithSeed:(int)s grid:(ccGridSize)gridSize duration:(ccTime)d
{
return [[[self alloc] initWithSeed:s grid:gridSize duration:d] autorelease];
}
-(id)initWithSeed:(int)s grid:(ccGridSize)gSize duration:(ccTime)d
{
if ( (self = [super initWithSize:gSize duration:d]) )
{
seed = s;
tilesOrder = nil;
tiles = nil;
}
return self;
}
-(id) copyWithZone: (NSZone*) zone
{
CCGridAction *copy = [[[self class] allocWithZone:zone] initWithSeed:seed grid:gridSize_ duration:duration_];
return copy;
}
-(void)dealloc
{
if ( tilesOrder ) free(tilesOrder);
if ( tiles ) free(tiles);
[super dealloc];
}
-(void)shuffle:(int*)array count:(NSUInteger)len
{
NSInteger i;
for( i = len - 1; i >= 0; i-- )
{
NSInteger j = rand() % (i+1);
int v = array[i];
array[i] = array[j];
array[j] = v;
}
}
-(ccGridSize)getDelta:(ccGridSize)pos
{
CGPoint pos2;
NSInteger idx = pos.x * gridSize_.y + pos.y;
pos2.x = tilesOrder[idx] / (int)gridSize_.y;
pos2.y = tilesOrder[idx] % (int)gridSize_.y;
return ccg(pos2.x - pos.x, pos2.y - pos.y);
}
-(void)placeTile:(ccGridSize)pos tile:(Tile)t
{
ccQuad3 coords = [self originalTile:pos];
CGPoint step = [[target_ grid] step];
coords.bl.x += (int)(t.position.x * step.x);
coords.bl.y += (int)(t.position.y * step.y);
coords.br.x += (int)(t.position.x * step.x);
coords.br.y += (int)(t.position.y * step.y);
coords.tl.x += (int)(t.position.x * step.x);
coords.tl.y += (int)(t.position.y * step.y);
coords.tr.x += (int)(t.position.x * step.x);
coords.tr.y += (int)(t.position.y * step.y);
[self setTile:pos coords:coords];
}
-(void)startWithTarget:(id)aTarget
{
[super startWithTarget:aTarget];
if ( seed != -1 )
srand(seed);
tilesCount = gridSize_.x * gridSize_.y;
tilesOrder = (int*)malloc(tilesCount*sizeof(int));
int i, j;
for( i = 0; i < tilesCount; i++ )
tilesOrder[i] = i;
[self shuffle:tilesOrder count:tilesCount];
tiles = malloc(tilesCount*sizeof(Tile));
Tile *tileArray = (Tile*)tiles;
for( i = 0; i < gridSize_.x; i++ )
{
for( j = 0; j < gridSize_.y; j++ )
{
tileArray->position = ccp(i,j);
tileArray->startPosition = ccp(i,j);
tileArray->delta = [self getDelta:ccg(i,j)];
tileArray++;
}
}
}
-(void)update:(ccTime)time
{
int i, j;
Tile *tileArray = (Tile*)tiles;
for( i = 0; i < gridSize_.x; i++ )
{
for( j = 0; j < gridSize_.y; j++ )
{
tileArray->position = ccpMult( ccp(tileArray->delta.x, tileArray->delta.y), time);
[self placeTile:ccg(i,j) tile:*tileArray];
tileArray++;
}
}
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark CCFadeOutTRTiles
@implementation CCFadeOutTRTiles
-(float)testFunc:(ccGridSize)pos time:(ccTime)time
{
CGPoint n = ccpMult( ccp(gridSize_.x,gridSize_.y), time);
if ( (n.x+n.y) == 0.0f )
return 1.0f;
return powf( (pos.x+pos.y) / (n.x+n.y), 6 );
}
-(void)turnOnTile:(ccGridSize)pos
{
[self setTile:pos coords:[self originalTile:pos]];
}
-(void)turnOffTile:(ccGridSize)pos
{
ccQuad3 coords;
bzero(&coords, sizeof(ccQuad3));
[self setTile:pos coords:coords];
}
-(void)transformTile:(ccGridSize)pos distance:(float)distance
{
ccQuad3 coords = [self originalTile:pos];
CGPoint step = [[target_ grid] step];
coords.bl.x += (step.x / 2) * (1.0f - distance);
coords.bl.y += (step.y / 2) * (1.0f - distance);
coords.br.x -= (step.x / 2) * (1.0f - distance);
coords.br.y += (step.y / 2) * (1.0f - distance);
coords.tl.x += (step.x / 2) * (1.0f - distance);
coords.tl.y -= (step.y / 2) * (1.0f - distance);
coords.tr.x -= (step.x / 2) * (1.0f - distance);
coords.tr.y -= (step.y / 2) * (1.0f - distance);
[self setTile:pos coords:coords];
}
-(void)update:(ccTime)time
{
int i, j;
for( i = 0; i < gridSize_.x; i++ )
{
for( j = 0; j < gridSize_.y; j++ )
{
float distance = [self testFunc:ccg(i,j) time:time];
if ( distance == 0 )
[self turnOffTile:ccg(i,j)];
else if ( distance < 1 )
[self transformTile:ccg(i,j) distance:distance];
else
[self turnOnTile:ccg(i,j)];
}
}
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark CCFadeOutBLTiles
@implementation CCFadeOutBLTiles
-(float)testFunc:(ccGridSize)pos time:(ccTime)time
{
CGPoint n = ccpMult(ccp(gridSize_.x, gridSize_.y), (1.0f-time));
if ( (pos.x+pos.y) == 0 )
return 1.0f;
return powf( (n.x+n.y) / (pos.x+pos.y), 6 );
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark CCFadeOutUpTiles
@implementation CCFadeOutUpTiles
-(float)testFunc:(ccGridSize)pos time:(ccTime)time
{
CGPoint n = ccpMult(ccp(gridSize_.x, gridSize_.y), time);
if ( n.y == 0 )
return 1.0f;
return powf( pos.y / n.y, 6 );
}
-(void)transformTile:(ccGridSize)pos distance:(float)distance
{
ccQuad3 coords = [self originalTile:pos];
CGPoint step = [[target_ grid] step];
coords.bl.y += (step.y / 2) * (1.0f - distance);
coords.br.y += (step.y / 2) * (1.0f - distance);
coords.tl.y -= (step.y / 2) * (1.0f - distance);
coords.tr.y -= (step.y / 2) * (1.0f - distance);
[self setTile:pos coords:coords];
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark CCFadeOutDownTiles
@implementation CCFadeOutDownTiles
-(float)testFunc:(ccGridSize)pos time:(ccTime)time
{
CGPoint n = ccpMult(ccp(gridSize_.x,gridSize_.y), (1.0f - time));
if ( pos.y == 0 )
return 1.0f;
return powf( n.y / pos.y, 6 );
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark TurnOffTiles
@implementation CCTurnOffTiles
+(id)actionWithSeed:(int)s grid:(ccGridSize)gridSize duration:(ccTime)d
{
return [[[self alloc] initWithSeed:s grid:gridSize duration:d] autorelease];
}
-(id)initWithSeed:(int)s grid:(ccGridSize)gSize duration:(ccTime)d
{
if ( (self = [super initWithSize:gSize duration:d]) )
{
seed = s;
tilesOrder = nil;
}
return self;
}
-(id) copyWithZone: (NSZone*) zone
{
CCGridAction *copy = [[[self class] allocWithZone:zone] initWithSeed:seed grid:gridSize_ duration:duration_];
return copy;
}
-(void)dealloc
{
if ( tilesOrder ) free(tilesOrder);
[super dealloc];
}
-(void)shuffle:(int*)array count:(NSUInteger)len
{
NSInteger i;
for( i = len - 1; i >= 0; i-- )
{
NSInteger j = rand() % (i+1);
int v = array[i];
array[i] = array[j];
array[j] = v;
}
}
-(void)turnOnTile:(ccGridSize)pos
{
[self setTile:pos coords:[self originalTile:pos]];
}
-(void)turnOffTile:(ccGridSize)pos
{
ccQuad3 coords;
bzero(&coords, sizeof(ccQuad3));
[self setTile:pos coords:coords];
}
-(void)startWithTarget:(id)aTarget
{
int i;
[super startWithTarget:aTarget];
if ( seed != -1 )
srand(seed);
tilesCount = gridSize_.x * gridSize_.y;
tilesOrder = (int*)malloc(tilesCount*sizeof(int));
for( i = 0; i < tilesCount; i++ )
tilesOrder[i] = i;
[self shuffle:tilesOrder count:tilesCount];
}
-(void)update:(ccTime)time
{
int i, l, t;
l = (int)(time * (float)tilesCount);
for( i = 0; i < tilesCount; i++ )
{
t = tilesOrder[i];
ccGridSize tilePos = ccg( t / gridSize_.y, t % gridSize_.y );
if ( i < l )
[self turnOffTile:tilePos];
else
[self turnOnTile:tilePos];
}
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark CCWavesTiles3D
@implementation CCWavesTiles3D
@synthesize amplitude;
@synthesize amplitudeRate;
+(id)actionWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d
{
return [[[self alloc] initWithWaves:wav amplitude:amp grid:gridSize duration:d] autorelease];
}
-(id)initWithWaves:(int)wav amplitude:(float)amp grid:(ccGridSize)gSize duration:(ccTime)d
{
if ( (self = [super initWithSize:gSize duration:d]) )
{
waves = wav;
amplitude = amp;
amplitudeRate = 1.0f;
}
return self;
}
-(id) copyWithZone: (NSZone*) zone
{
CCGridAction *copy = [[[self class] allocWithZone:zone] initWithWaves:waves amplitude:amplitude grid:gridSize_ duration:duration_];
return copy;
}
-(void)update:(ccTime)time
{
int i, j;
for( i = 0; i < gridSize_.x; i++ )
{
for( j = 0; j < gridSize_.y; j++ )
{
ccQuad3 coords = [self originalTile:ccg(i,j)];
coords.bl.z = (sinf(time*(CGFloat)M_PI*waves*2 + (coords.bl.y+coords.bl.x) * .01f) * amplitude * amplitudeRate );
coords.br.z = coords.bl.z;
coords.tl.z = coords.bl.z;
coords.tr.z = coords.bl.z;
[self setTile:ccg(i,j) coords:coords];
}
}
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark CCJumpTiles3D
@implementation CCJumpTiles3D
@synthesize amplitude;
@synthesize amplitudeRate;
+(id)actionWithJumps:(int)j amplitude:(float)amp grid:(ccGridSize)gridSize duration:(ccTime)d
{
return [[[self alloc] initWithJumps:j amplitude:amp grid:gridSize duration:d] autorelease];
}
-(id)initWithJumps:(int)j amplitude:(float)amp grid:(ccGridSize)gSize duration:(ccTime)d
{
if ( (self = [super initWithSize:gSize duration:d]) )
{
jumps = j;
amplitude = amp;
amplitudeRate = 1.0f;
}
return self;
}
-(id) copyWithZone: (NSZone*) zone
{
CCGridAction *copy = [[[self class] allocWithZone:zone] initWithJumps:jumps amplitude:amplitude grid:gridSize_ duration:duration_];
return copy;
}
-(void)update:(ccTime)time
{
int i, j;
float sinz = (sinf((CGFloat)M_PI*time*jumps*2) * amplitude * amplitudeRate );
float sinz2 = (sinf((CGFloat)M_PI*(time*jumps*2 + 1)) * amplitude * amplitudeRate );
for( i = 0; i < gridSize_.x; i++ )
{
for( j = 0; j < gridSize_.y; j++ )
{
ccQuad3 coords = [self originalTile:ccg(i,j)];
if ( ((i+j) % 2) == 0 )
{
coords.bl.z += sinz;
coords.br.z += sinz;
coords.tl.z += sinz;
coords.tr.z += sinz;
}
else
{
coords.bl.z += sinz2;
coords.br.z += sinz2;
coords.tl.z += sinz2;
coords.tr.z += sinz2;
}
[self setTile:ccg(i,j) coords:coords];
}
}
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark SplitRows
@implementation CCSplitRows
+(id)actionWithRows:(int)r duration:(ccTime)d
{
return [[[self alloc] initWithRows:r duration:d] autorelease];
}
-(id)initWithRows:(int)r duration:(ccTime)d
{
rows = r;
return [super initWithSize:ccg(1,r) duration:d];
}
-(id) copyWithZone: (NSZone*) zone
{
CCGridAction *copy = [[[self class] allocWithZone:zone] initWithRows:rows duration:duration_];
return copy;
}
-(void)startWithTarget:(id)aTarget
{
[super startWithTarget:aTarget];
winSize = [[CCDirector sharedDirector] winSizeInPixels];
}
-(void)update:(ccTime)time
{
int j;
for( j = 0; j < gridSize_.y; j++ )
{
ccQuad3 coords = [self originalTile:ccg(0,j)];
float direction = 1;
if ( (j % 2 ) == 0 )
direction = -1;
coords.bl.x += direction * winSize.width * time;
coords.br.x += direction * winSize.width * time;
coords.tl.x += direction * winSize.width * time;
coords.tr.x += direction * winSize.width * time;
[self setTile:ccg(0,j) coords:coords];
}
}
@end
////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark CCSplitCols
@implementation CCSplitCols
+(id)actionWithCols:(int)c duration:(ccTime)d
{
return [[[self alloc] initWithCols:c duration:d] autorelease];
}
-(id)initWithCols:(int)c duration:(ccTime)d
{
cols = c;
return [super initWithSize:ccg(c,1) duration:d];
}
-(id) copyWithZone: (NSZone*) zone
{
CCGridAction *copy = [[[self class] allocWithZone:zone] initWithCols:cols duration:duration_];
return copy;
}
-(void)startWithTarget:(id)aTarget
{
[super startWithTarget:aTarget];
winSize = [[CCDirector sharedDirector] winSizeInPixels];
}
-(void)update:(ccTime)time
{
int i;
for( i = 0; i < gridSize_.x; i++ )
{
ccQuad3 coords = [self originalTile:ccg(i,0)];
float direction = 1;
if ( (i % 2 ) == 0 )
direction = -1;
coords.bl.y += direction * winSize.height * time;
coords.br.y += direction * winSize.height * time;
coords.tl.y += direction * winSize.height * time;
coords.tr.y += direction * winSize.height * time;
[self setTile:ccg(i,0) coords:coords];
}
}
@end