From 9cd57b731ab1c666d4a1cb725538fdc137763d12 Mon Sep 17 00:00:00 2001 From: Starla Insigna Date: Sat, 30 Jul 2011 11:19:14 -0400 Subject: Initial commit (version 0.2.1) --- libs/cocos2d/CCParticleSystem.m | 808 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 808 insertions(+) create mode 100755 libs/cocos2d/CCParticleSystem.m (limited to 'libs/cocos2d/CCParticleSystem.m') diff --git a/libs/cocos2d/CCParticleSystem.m b/libs/cocos2d/CCParticleSystem.m new file mode 100755 index 0000000..742676e --- /dev/null +++ b/libs/cocos2d/CCParticleSystem.m @@ -0,0 +1,808 @@ +/* + * cocos2d for iPhone: http://www.cocos2d-iphone.org + * + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011 Zynga Inc. + * + * 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. + * + */ + + +// ideas taken from: +// . The ocean spray in your face [Jeff Lander] +// http://www.double.co.nz/dust/col0798.pdf +// . Building an Advanced Particle System [John van der Burg] +// http://www.gamasutra.com/features/20000623/vanderburg_01.htm +// . LOVE game engine +// http://love2d.org/ +// +// +// Radius mode support, from 71 squared +// http://particledesigner.71squared.com/ +// +// IMPORTANT: Particle Designer is supported by cocos2d, but +// 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d, +// cocos2d uses a another approach, but the results are almost identical. +// + +// opengl +#import "Platforms/CCGL.h" + +// cocos2d +#import "ccConfig.h" +#if CC_ENABLE_PROFILERS +#import "Support/CCProfiling.h" +#endif +#import "CCParticleSystem.h" +#import "CCTextureCache.h" +#import "ccMacros.h" + +// support +#import "Support/OpenGL_Internal.h" +#import "Support/CGPointExtension.h" +#import "Support/base64.h" +#import "Support/ZipUtils.h" +#import "Support/CCFileUtils.h" + +@implementation CCParticleSystem +@synthesize active, duration; +@synthesize sourcePosition, posVar; +@synthesize particleCount; +@synthesize life, lifeVar; +@synthesize angle, angleVar; +@synthesize startColor, startColorVar, endColor, endColorVar; +@synthesize startSpin, startSpinVar, endSpin, endSpinVar; +@synthesize emissionRate; +@synthesize totalParticles; +@synthesize startSize, startSizeVar; +@synthesize endSize, endSizeVar; +@synthesize blendFunc = blendFunc_; +@synthesize positionType = positionType_; +@synthesize autoRemoveOnFinish = autoRemoveOnFinish_; +@synthesize emitterMode = emitterMode_; + + ++(id) particleWithFile:(NSString*) plistFile +{ + return [[[self alloc] initWithFile:plistFile] autorelease]; +} + +-(id) init { + NSAssert(NO, @"CCParticleSystem: Init not supported."); + [self release]; + return nil; +} + +-(id) initWithFile:(NSString *)plistFile +{ + NSString *path = [CCFileUtils fullPathFromRelativePath:plistFile]; + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; + + NSAssert( dict != nil, @"Particles: file not found"); + return [self initWithDictionary:dict]; +} + +-(id) initWithDictionary:(NSDictionary *)dictionary +{ + NSUInteger maxParticles = [[dictionary valueForKey:@"maxParticles"] intValue]; + // self, not super + if ((self=[self initWithTotalParticles:maxParticles] ) ) { + + // angle + angle = [[dictionary valueForKey:@"angle"] floatValue]; + angleVar = [[dictionary valueForKey:@"angleVariance"] floatValue]; + + // duration + duration = [[dictionary valueForKey:@"duration"] floatValue]; + + // blend function + blendFunc_.src = [[dictionary valueForKey:@"blendFuncSource"] intValue]; + blendFunc_.dst = [[dictionary valueForKey:@"blendFuncDestination"] intValue]; + + // color + float r,g,b,a; + + r = [[dictionary valueForKey:@"startColorRed"] floatValue]; + g = [[dictionary valueForKey:@"startColorGreen"] floatValue]; + b = [[dictionary valueForKey:@"startColorBlue"] floatValue]; + a = [[dictionary valueForKey:@"startColorAlpha"] floatValue]; + startColor = (ccColor4F) {r,g,b,a}; + + r = [[dictionary valueForKey:@"startColorVarianceRed"] floatValue]; + g = [[dictionary valueForKey:@"startColorVarianceGreen"] floatValue]; + b = [[dictionary valueForKey:@"startColorVarianceBlue"] floatValue]; + a = [[dictionary valueForKey:@"startColorVarianceAlpha"] floatValue]; + startColorVar = (ccColor4F) {r,g,b,a}; + + r = [[dictionary valueForKey:@"finishColorRed"] floatValue]; + g = [[dictionary valueForKey:@"finishColorGreen"] floatValue]; + b = [[dictionary valueForKey:@"finishColorBlue"] floatValue]; + a = [[dictionary valueForKey:@"finishColorAlpha"] floatValue]; + endColor = (ccColor4F) {r,g,b,a}; + + r = [[dictionary valueForKey:@"finishColorVarianceRed"] floatValue]; + g = [[dictionary valueForKey:@"finishColorVarianceGreen"] floatValue]; + b = [[dictionary valueForKey:@"finishColorVarianceBlue"] floatValue]; + a = [[dictionary valueForKey:@"finishColorVarianceAlpha"] floatValue]; + endColorVar = (ccColor4F) {r,g,b,a}; + + // particle size + startSize = [[dictionary valueForKey:@"startParticleSize"] floatValue]; + startSizeVar = [[dictionary valueForKey:@"startParticleSizeVariance"] floatValue]; + endSize = [[dictionary valueForKey:@"finishParticleSize"] floatValue]; + endSizeVar = [[dictionary valueForKey:@"finishParticleSizeVariance"] floatValue]; + + + // position + float x = [[dictionary valueForKey:@"sourcePositionx"] floatValue]; + float y = [[dictionary valueForKey:@"sourcePositiony"] floatValue]; + self.position = ccp(x,y); + posVar.x = [[dictionary valueForKey:@"sourcePositionVariancex"] floatValue]; + posVar.y = [[dictionary valueForKey:@"sourcePositionVariancey"] floatValue]; + + + // Spinning + startSpin = [[dictionary valueForKey:@"rotationStart"] floatValue]; + startSpinVar = [[dictionary valueForKey:@"rotationStartVariance"] floatValue]; + endSpin = [[dictionary valueForKey:@"rotationEnd"] floatValue]; + endSpinVar = [[dictionary valueForKey:@"rotationEndVariance"] floatValue]; + + emitterMode_ = [[dictionary valueForKey:@"emitterType"] intValue]; + + // Mode A: Gravity + tangential accel + radial accel + if( emitterMode_ == kCCParticleModeGravity ) { + // gravity + mode.A.gravity.x = [[dictionary valueForKey:@"gravityx"] floatValue]; + mode.A.gravity.y = [[dictionary valueForKey:@"gravityy"] floatValue]; + + // + // speed + mode.A.speed = [[dictionary valueForKey:@"speed"] floatValue]; + mode.A.speedVar = [[dictionary valueForKey:@"speedVariance"] floatValue]; + + // radial acceleration + NSString *tmp = [dictionary valueForKey:@"radialAcceleration"]; + mode.A.radialAccel = tmp ? [tmp floatValue] : 0; + + tmp = [dictionary valueForKey:@"radialAccelVariance"]; + mode.A.radialAccelVar = tmp ? [tmp floatValue] : 0; + + // tangential acceleration + tmp = [dictionary valueForKey:@"tangentialAcceleration"]; + mode.A.tangentialAccel = tmp ? [tmp floatValue] : 0; + + tmp = [dictionary valueForKey:@"tangentialAccelVariance"]; + mode.A.tangentialAccelVar = tmp ? [tmp floatValue] : 0; + } + + + // or Mode B: radius movement + else if( emitterMode_ == kCCParticleModeRadius ) { + float maxRadius = [[dictionary valueForKey:@"maxRadius"] floatValue]; + float maxRadiusVar = [[dictionary valueForKey:@"maxRadiusVariance"] floatValue]; + float minRadius = [[dictionary valueForKey:@"minRadius"] floatValue]; + + mode.B.startRadius = maxRadius; + mode.B.startRadiusVar = maxRadiusVar; + mode.B.endRadius = minRadius; + mode.B.endRadiusVar = 0; + mode.B.rotatePerSecond = [[dictionary valueForKey:@"rotatePerSecond"] floatValue]; + mode.B.rotatePerSecondVar = [[dictionary valueForKey:@"rotatePerSecondVariance"] floatValue]; + + } else { + NSAssert( NO, @"Invalid emitterType in config file"); + } + + // life span + life = [[dictionary valueForKey:@"particleLifespan"] floatValue]; + lifeVar = [[dictionary valueForKey:@"particleLifespanVariance"] floatValue]; + + // emission Rate + emissionRate = totalParticles/life; + + // texture + // Try to get the texture from the cache + NSString *textureName = [dictionary valueForKey:@"textureFileName"]; + + CCTexture2D *tex = [[CCTextureCache sharedTextureCache] addImage:textureName]; + + if( tex ) + self.texture = tex; + + else { + + NSString *textureData = [dictionary valueForKey:@"textureImageData"]; + NSAssert( textureData, @"CCParticleSystem: Couldn't load texture"); + + // if it fails, try to get it from the base64-gzipped data + unsigned char *buffer = NULL; + int len = base64Decode((unsigned char*)[textureData UTF8String], (unsigned int)[textureData length], &buffer); + NSAssert( buffer != NULL, @"CCParticleSystem: error decoding textureImageData"); + + unsigned char *deflated = NULL; + NSUInteger deflatedLen = ccInflateMemory(buffer, len, &deflated); + free( buffer ); + + NSAssert( deflated != NULL, @"CCParticleSystem: error ungzipping textureImageData"); + NSData *data = [[NSData alloc] initWithBytes:deflated length:deflatedLen]; + +#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED + UIImage *image = [[UIImage alloc] initWithData:data]; +#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) + NSBitmapImageRep *image = [[NSBitmapImageRep alloc] initWithData:data]; +#endif + + free(deflated); deflated = NULL; + + self.texture = [[CCTextureCache sharedTextureCache] addCGImage:[image CGImage] forKey:textureName]; + [data release]; + [image release]; + } + + NSAssert( [self texture] != NULL, @"CCParticleSystem: error loading the texture"); + + } + + return self; +} + +-(id) initWithTotalParticles:(NSUInteger) numberOfParticles +{ + if( (self=[super init]) ) { + + totalParticles = numberOfParticles; + + particles = calloc( totalParticles, sizeof(tCCParticle) ); + + if( ! particles ) { + NSLog(@"Particle system: not enough memory"); + [self release]; + return nil; + } + + // default, active + active = YES; + + // default blend function + blendFunc_ = (ccBlendFunc) { CC_BLEND_SRC, CC_BLEND_DST }; + + // default movement type; + positionType_ = kCCPositionTypeFree; + + // by default be in mode A: + emitterMode_ = kCCParticleModeGravity; + + // default: modulate + // XXX: not used + // colorModulate = YES; + + autoRemoveOnFinish_ = NO; + + // profiling +#if CC_ENABLE_PROFILERS + _profilingTimer = [[CCProfiler timerWithName:@"particle system" andInstance:self] retain]; +#endif + + // Optimization: compile udpateParticle method + updateParticleSel = @selector(updateQuadWithParticle:newPosition:); + updateParticleImp = (CC_UPDATE_PARTICLE_IMP) [self methodForSelector:updateParticleSel]; + + // udpate after action in run! + [self scheduleUpdateWithPriority:1]; + + } + + return self; +} + +-(void) dealloc +{ + free( particles ); + + [texture_ release]; + // profiling +#if CC_ENABLE_PROFILERS + [CCProfiler releaseTimer:_profilingTimer]; +#endif + + [super dealloc]; +} + +-(BOOL) addParticle +{ + if( [self isFull] ) + return NO; + + tCCParticle * particle = &particles[ particleCount ]; + + [self initParticle: particle]; + particleCount++; + + return YES; +} + +-(void) initParticle: (tCCParticle*) particle +{ + + // timeToLive + // no negative life. prevent division by 0 + particle->timeToLive = life + lifeVar * CCRANDOM_MINUS1_1(); + particle->timeToLive = MAX(0, particle->timeToLive); + + // position + particle->pos.x = sourcePosition.x + posVar.x * CCRANDOM_MINUS1_1(); + particle->pos.x *= CC_CONTENT_SCALE_FACTOR(); + particle->pos.y = sourcePosition.y + posVar.y * CCRANDOM_MINUS1_1(); + particle->pos.y *= CC_CONTENT_SCALE_FACTOR(); + + // Color + ccColor4F start; + start.r = clampf( startColor.r + startColorVar.r * CCRANDOM_MINUS1_1(), 0, 1); + start.g = clampf( startColor.g + startColorVar.g * CCRANDOM_MINUS1_1(), 0, 1); + start.b = clampf( startColor.b + startColorVar.b * CCRANDOM_MINUS1_1(), 0, 1); + start.a = clampf( startColor.a + startColorVar.a * CCRANDOM_MINUS1_1(), 0, 1); + + ccColor4F end; + end.r = clampf( endColor.r + endColorVar.r * CCRANDOM_MINUS1_1(), 0, 1); + end.g = clampf( endColor.g + endColorVar.g * CCRANDOM_MINUS1_1(), 0, 1); + end.b = clampf( endColor.b + endColorVar.b * CCRANDOM_MINUS1_1(), 0, 1); + end.a = clampf( endColor.a + endColorVar.a * CCRANDOM_MINUS1_1(), 0, 1); + + particle->color = start; + particle->deltaColor.r = (end.r - start.r) / particle->timeToLive; + particle->deltaColor.g = (end.g - start.g) / particle->timeToLive; + particle->deltaColor.b = (end.b - start.b) / particle->timeToLive; + particle->deltaColor.a = (end.a - start.a) / particle->timeToLive; + + // size + float startS = startSize + startSizeVar * CCRANDOM_MINUS1_1(); + startS = MAX(0, startS); // No negative value + startS *= CC_CONTENT_SCALE_FACTOR(); + + particle->size = startS; + if( endSize == kCCParticleStartSizeEqualToEndSize ) + particle->deltaSize = 0; + else { + float endS = endSize + endSizeVar * CCRANDOM_MINUS1_1(); + endS = MAX(0, endS); // No negative values + endS *= CC_CONTENT_SCALE_FACTOR(); + particle->deltaSize = (endS - startS) / particle->timeToLive; + } + + // rotation + float startA = startSpin + startSpinVar * CCRANDOM_MINUS1_1(); + float endA = endSpin + endSpinVar * CCRANDOM_MINUS1_1(); + particle->rotation = startA; + particle->deltaRotation = (endA - startA) / particle->timeToLive; + + // position + if( positionType_ == kCCPositionTypeFree ) { + CGPoint p = [self convertToWorldSpace:CGPointZero]; + particle->startPos = ccpMult( p, CC_CONTENT_SCALE_FACTOR() ); + } + else if( positionType_ == kCCPositionTypeRelative ) { + particle->startPos = ccpMult( position_, CC_CONTENT_SCALE_FACTOR() ); + } + + // direction + float a = CC_DEGREES_TO_RADIANS( angle + angleVar * CCRANDOM_MINUS1_1() ); + + // Mode Gravity: A + if( emitterMode_ == kCCParticleModeGravity ) { + + CGPoint v = {cosf( a ), sinf( a )}; + float s = mode.A.speed + mode.A.speedVar * CCRANDOM_MINUS1_1(); + s *= CC_CONTENT_SCALE_FACTOR(); + + // direction + particle->mode.A.dir = ccpMult( v, s ); + + // radial accel + particle->mode.A.radialAccel = mode.A.radialAccel + mode.A.radialAccelVar * CCRANDOM_MINUS1_1(); + particle->mode.A.radialAccel *= CC_CONTENT_SCALE_FACTOR(); + + // tangential accel + particle->mode.A.tangentialAccel = mode.A.tangentialAccel + mode.A.tangentialAccelVar * CCRANDOM_MINUS1_1(); + particle->mode.A.tangentialAccel *= CC_CONTENT_SCALE_FACTOR(); + + } + + // Mode Radius: B + else { + // Set the default diameter of the particle from the source position + float startRadius = mode.B.startRadius + mode.B.startRadiusVar * CCRANDOM_MINUS1_1(); + float endRadius = mode.B.endRadius + mode.B.endRadiusVar * CCRANDOM_MINUS1_1(); + + startRadius *= CC_CONTENT_SCALE_FACTOR(); + endRadius *= CC_CONTENT_SCALE_FACTOR(); + + particle->mode.B.radius = startRadius; + + if( mode.B.endRadius == kCCParticleStartRadiusEqualToEndRadius ) + particle->mode.B.deltaRadius = 0; + else + particle->mode.B.deltaRadius = (endRadius - startRadius) / particle->timeToLive; + + particle->mode.B.angle = a; + particle->mode.B.degreesPerSecond = CC_DEGREES_TO_RADIANS(mode.B.rotatePerSecond + mode.B.rotatePerSecondVar * CCRANDOM_MINUS1_1()); + } +} + +-(void) stopSystem +{ + active = NO; + elapsed = duration; + emitCounter = 0; +} + +-(void) resetSystem +{ + active = YES; + elapsed = 0; + for(particleIdx = 0; particleIdx < particleCount; ++particleIdx) { + tCCParticle *p = &particles[particleIdx]; + p->timeToLive = 0; + } +} + +-(BOOL) isFull +{ + return (particleCount == totalParticles); +} + +#pragma mark ParticleSystem - MainLoop +-(void) update: (ccTime) dt +{ + if( active && emissionRate ) { + float rate = 1.0f / emissionRate; + emitCounter += dt; + while( particleCount < totalParticles && emitCounter > rate ) { + [self addParticle]; + emitCounter -= rate; + } + + elapsed += dt; + if(duration != -1 && duration < elapsed) + [self stopSystem]; + } + + particleIdx = 0; + + +#if CC_ENABLE_PROFILERS + CCProfilingBeginTimingBlock(_profilingTimer); +#endif + + + CGPoint currentPosition = CGPointZero; + if( positionType_ == kCCPositionTypeFree ) { + currentPosition = [self convertToWorldSpace:CGPointZero]; + currentPosition.x *= CC_CONTENT_SCALE_FACTOR(); + currentPosition.y *= CC_CONTENT_SCALE_FACTOR(); + } + else if( positionType_ == kCCPositionTypeRelative ) { + currentPosition = position_; + currentPosition.x *= CC_CONTENT_SCALE_FACTOR(); + currentPosition.y *= CC_CONTENT_SCALE_FACTOR(); + } + + while( particleIdx < particleCount ) + { + tCCParticle *p = &particles[particleIdx]; + + // life + p->timeToLive -= dt; + + if( p->timeToLive > 0 ) { + + // Mode A: gravity, direction, tangential accel & radial accel + if( emitterMode_ == kCCParticleModeGravity ) { + CGPoint tmp, radial, tangential; + + radial = CGPointZero; + // radial acceleration + if(p->pos.x || p->pos.y) + radial = ccpNormalize(p->pos); + + tangential = radial; + radial = ccpMult(radial, p->mode.A.radialAccel); + + // tangential acceleration + float newy = tangential.x; + tangential.x = -tangential.y; + tangential.y = newy; + tangential = ccpMult(tangential, p->mode.A.tangentialAccel); + + // (gravity + radial + tangential) * dt + tmp = ccpAdd( ccpAdd( radial, tangential), mode.A.gravity); + tmp = ccpMult( tmp, dt); + p->mode.A.dir = ccpAdd( p->mode.A.dir, tmp); + tmp = ccpMult(p->mode.A.dir, dt); + p->pos = ccpAdd( p->pos, tmp ); + } + + // Mode B: radius movement + else { + // Update the angle and radius of the particle. + p->mode.B.angle += p->mode.B.degreesPerSecond * dt; + p->mode.B.radius += p->mode.B.deltaRadius * dt; + + p->pos.x = - cosf(p->mode.B.angle) * p->mode.B.radius; + p->pos.y = - sinf(p->mode.B.angle) * p->mode.B.radius; + } + + // color + p->color.r += (p->deltaColor.r * dt); + p->color.g += (p->deltaColor.g * dt); + p->color.b += (p->deltaColor.b * dt); + p->color.a += (p->deltaColor.a * dt); + + // size + p->size += (p->deltaSize * dt); + p->size = MAX( 0, p->size ); + + // angle + p->rotation += (p->deltaRotation * dt); + + // + // update values in quad + // + + CGPoint newPos; + + if( positionType_ == kCCPositionTypeFree || positionType_ == kCCPositionTypeRelative ) { + CGPoint diff = ccpSub( currentPosition, p->startPos ); + newPos = ccpSub(p->pos, diff); + + } else + newPos = p->pos; + + + updateParticleImp(self, updateParticleSel, p, newPos); + + // update particle counter + particleIdx++; + + } else { + // life < 0 + if( particleIdx != particleCount-1 ) + particles[particleIdx] = particles[particleCount-1]; + particleCount--; + + if( particleCount == 0 && autoRemoveOnFinish_ ) { + [self unscheduleUpdate]; + [parent_ removeChild:self cleanup:YES]; + return; + } + } + } + +#if CC_ENABLE_PROFILERS + CCProfilingEndTimingBlock(_profilingTimer); +#endif + +#ifdef CC_USES_VBO + [self postStep]; +#endif +} + +-(void) updateQuadWithParticle:(tCCParticle*)particle newPosition:(CGPoint)pos; +{ + // should be overriden +} + +-(void) postStep +{ + // should be overriden +} + +#pragma mark ParticleSystem - CCTexture protocol + +-(void) setTexture:(CCTexture2D*) texture +{ + [texture_ release]; + texture_ = [texture retain]; + + // If the new texture has No premultiplied alpha, AND the blendFunc hasn't been changed, then update it + if( texture_ && ! [texture hasPremultipliedAlpha] && + ( blendFunc_.src == CC_BLEND_SRC && blendFunc_.dst == CC_BLEND_DST ) ) { + + blendFunc_.src = GL_SRC_ALPHA; + blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; + } +} + +-(CCTexture2D*) texture +{ + return texture_; +} + +#pragma mark ParticleSystem - Additive Blending +-(void) setBlendAdditive:(BOOL)additive +{ + if( additive ) { + blendFunc_.src = GL_SRC_ALPHA; + blendFunc_.dst = GL_ONE; + + } else { + + if( texture_ && ! [texture_ hasPremultipliedAlpha] ) { + blendFunc_.src = GL_SRC_ALPHA; + blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; + } else { + blendFunc_.src = CC_BLEND_SRC; + blendFunc_.dst = CC_BLEND_DST; + } + } +} + +-(BOOL) blendAdditive +{ + return( blendFunc_.src == GL_SRC_ALPHA && blendFunc_.dst == GL_ONE); +} + +#pragma mark ParticleSystem - Properties of Gravity Mode +-(void) setTangentialAccel:(float)t +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + mode.A.tangentialAccel = t; +} +-(float) tangentialAccel +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + return mode.A.tangentialAccel; +} + +-(void) setTangentialAccelVar:(float)t +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + mode.A.tangentialAccelVar = t; +} +-(float) tangentialAccelVar +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + return mode.A.tangentialAccelVar; +} + +-(void) setRadialAccel:(float)t +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + mode.A.radialAccel = t; +} +-(float) radialAccel +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + return mode.A.radialAccel; +} + +-(void) setRadialAccelVar:(float)t +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + mode.A.radialAccelVar = t; +} +-(float) radialAccelVar +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + return mode.A.radialAccelVar; +} + +-(void) setGravity:(CGPoint)g +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + mode.A.gravity = g; +} +-(CGPoint) gravity +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + return mode.A.gravity; +} + +-(void) setSpeed:(float)speed +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + mode.A.speed = speed; +} +-(float) speed +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + return mode.A.speed; +} + +-(void) setSpeedVar:(float)speedVar +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + mode.A.speedVar = speedVar; +} +-(float) speedVar +{ + NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); + return mode.A.speedVar; +} + +#pragma mark ParticleSystem - Properties of Radius Mode + +-(void) setStartRadius:(float)startRadius +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + mode.B.startRadius = startRadius; +} +-(float) startRadius +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + return mode.B.startRadius; +} + +-(void) setStartRadiusVar:(float)startRadiusVar +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + mode.B.startRadiusVar = startRadiusVar; +} +-(float) startRadiusVar +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + return mode.B.startRadiusVar; +} + +-(void) setEndRadius:(float)endRadius +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + mode.B.endRadius = endRadius; +} +-(float) endRadius +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + return mode.B.endRadius; +} + +-(void) setEndRadiusVar:(float)endRadiusVar +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + mode.B.endRadiusVar = endRadiusVar; +} +-(float) endRadiusVar +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + return mode.B.endRadiusVar; +} + +-(void) setRotatePerSecond:(float)degrees +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + mode.B.rotatePerSecond = degrees; +} +-(float) rotatePerSecond +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + return mode.B.rotatePerSecond; +} + +-(void) setRotatePerSecondVar:(float)degrees +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + mode.B.rotatePerSecondVar = degrees; +} +-(float) rotatePerSecondVar +{ + NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); + return mode.B.rotatePerSecondVar; +} +@end + + -- cgit 1.4.1