Posts Tagged ‘Core Animation’

Barebones CAEmitterLayer aka Particle Effects

Wednesday, February 24th, 2010

CAEmitterLayer: use to create particle effects. Each particle is an instance of CAEmitterCell. (10.6) – cocoadevcentral

How could you not be intrigued? Particle Effects! Well I’ve always been interested in Particle Generators, and there’s one right here in Snow Leopard. How exciting. /claps.

I recently took a look at the Fire and Fireworks sample code that Apple and was duly impressed by what Core Animation provides for so little cost both code-wise and CPU resources. So I decided to write the simplest – barebones – CAEmitterLayer code where I was only dependant on the NSView it draws on.

There’s no fancy-pants stuff going on here, just a raw, simple, single particle effect. But it gives you a great perspective on how it works and the minimal code required to have a great particle animation.

Screenshot of this project

If you’re starting afresh you’re going to need to tell your project that we want to use Core Animation so:

Looking at CAEmitterLayer briefly (and ignoring setting up Interface Builder & the Nib) in our header file we simply need a CAEmitterLayer:

IBOutlet NSView *view;
CALayer *rootLayer;
CAEmitterLayer *emitter;

Where as the implementation file is going to need a whole lot of data for the Emitter plus we need to create a CAEmitterCell for the particle itself.

//Create the emitter layer
emitter = [CAEmitterLayer layer];
emitter.emitterPosition = CGPointMake(CGRectGetMidX(rootLayer.bounds), CGRectGetMidY(rootLayer.bounds));
emitter.emitterMode = kCAEmitterLayerOutline;
emitter.emitterShape = kCAEmitterLayerCircle;
emitter.renderMode = kCAEmitterLayerAdditive;
emitter.emitterSize = CGSizeMake(50 * multiplier, 0);
 
//Create the emitter cell
CAEmitterCell* particle = [CAEmitterCell emitterCell];
particle.emissionLongitude = M_PI;
particle.birthRate = multiplier * 1000.0;
particle.lifetime = multiplier;
particle.lifetimeRange = multiplier * 0.35;
particle.velocity = 180;
particle.velocityRange = 130;
particle.emissionRange = 1.1;
particle.scaleSpeed = 0.3;
CGColorRef color = CGColorCreateGenericRGB(0.3, 0.4, 0.9, 0.10);
particle.color = color;
CGColorRelease(color);
particle.contents = (id) [self CGImageNamed:@"spark.png"];

For the complete implementation file or the complete project please feel free to grab the source code from the bitbucket project.

Core Animation CAConstraint Grid-Cell Layout

Tuesday, February 3rd, 2009

I really wanted to get a nice Grid Layout using CAConstraint, but I found the situation getting very complex very fast as each Cell needed to be able to reference the location of the last Cell and whether or not the Cell needed to drop down to a new Row, and at times needed to also reference the @”superlayer”. There has to be a better way, right?

CAConstraint Grid-Cell Layout with Animations

After a little digging around I was able to find an amazing Hot Chocolate blog post which showed a fantastic trick when laying out the Cells without having to reference the prior Cell. This approach takes advantage of knowing the Cell Row/Column position plus using the Scale: attribute of the CAConstraint on the @”superlayer” and it works like a charm.

[CAConstraint constraintWithAttribute: kCAConstraintWidth
relativeTo: @"superlayer"
attribute: kCAConstraintWidth
scale: 1.0 / columns
offset: 0]];

Want to change the number of Cells in the Grid? Modify these variables in this method:

- (void)layoutCellsInGridLayer:(CALayer *)layer {
	int columns = 6;
	int rows = 6;...

Also to give the project a little bit of “wow” here’s some random Y rotation on a Cell Layer:

- (void)setupFlipAnimationOnLayer:(CALayer *)layer {
	float duration = (float)frandom(0.5, 5.0);
 
	CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
	animation.fromValue = [NSNumber numberWithDouble:-1.0f * M_PI];
	animation.toValue = [NSNumber numberWithDouble:1.0f * M_PI];
	animation.duration = duration;
	animation.repeatCount = 1e100f;
	animation.beginTime = CACurrentMediaTime() + frandom(0.1, 30);
	animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
 
	[layer addAnimation:animation forKey:@"rotationY"];
}

To get the nice 3D perspective look the project needs the following code:

- (void)setupPerspectiveWithX:(float)x andY:(float)y {
	CATransform3D transform = CATransform3DMakeRotation(x, 0, 1, 0);
	transform = CATransform3DRotate(transform, y, 1, 0, 0);
	float zDistance = -450;
	transform.m34 = 1.0 / -zDistance;
	gridLayer.sublayerTransform = transform;
}

And one last final note: take a look in createCellInParentLayer: and you will see layer.contents. If you can provide your own image the layer will automatically Fill (layer.contentsGravity = kCAGravityResizeAspectFill;) and Mask (layer.masksToBounds = YES;) to make it fit.

You can grab the code here or download the binary here (requires Leopard).

Why is CAConstraint not working?

Monday, February 2nd, 2009

So you’re having problems with CAConstraint? It seems like no matter what you do the Constraint isn’t being applied to the Sublayer? And you’re CALayers are appearing in weird positions? Or not appearing at all?

Well the answer for me is surprisingly simple (and embarrassing)

1
2
3
4
[sublayer addConstraint:
[CAConstraint constraintWithAttribute:kCAConstraintMidX 
relativeTo:@"superlayer"
attribute:kCAConstraintMidX]]

Now see that that @”superlayer”? Notice that it’s not a Uppercase “L” as I was using “superLayer” where upon Core Animation was unable to find the layer “superLayer” and therefore have nothing to do with the constraints.

Cocoaheads Jan 5 – Core Animation

Monday, January 5th, 2009

Today I did a little talk at Cocoaheads Brisbane, Australia. It was on Core Animation and I made a very very very very very simple application which would rotate a single image using CATransform3DIdentity to give it a nice perspective 3D rotation look.

Here’s the full Xcode 3.1 project: Download.

If you’re interested solely in the transformation here’s the code:

float zDistance = 850;
CATransform3D sublayerTransform = CATransform3DIdentity;
sublayerTransform.m34 = 1.0 / -zDistance;
subLayer.transform = sublayerTransform;
 
CABasicAnimation *flipAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
flipAnimation.toValue = [NSNumber numberWithDouble:1.0f * M_PI];
flipAnimation.autoreverses = YES;
flipAnimation.duration = 2.0f;
flipAnimation.repeatCount = 1e100f;
flipAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[subLayer addAnimation:flipAnimation forKey:@"flip"];

Where subLayer == your Core Animation layer you want to rotate.

Reference: Core Animation for Mac OS X and the iPhone and Mike Lee.