Suspend Particles in CAEmitterLayer - ios

I have the following code that adds particles to a UIView named ParentView at the center of some other UIView:
CAEmitterLayer *emitterLayer = [CAEmitterLayer layer];
emitterLayer.emitterPosition = CGPointMake(view.center.x, view.center.y - view.frame.size.height / 3);
emitterLayer.emitterZPosition = 10;
emitterLayer.emitterSize = CGSizeMake(view.bounds.size.width, 0);
emitterLayer.emitterShape = kCAEmitterLayerSphere;
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
emitterCell.scale = 0.1;
emitterCell.scaleRange = 0.2;
emitterCell.emissionRange = 45;
emitterCell.lifetime = 0.75;
emitterCell.birthRate = 60;
emitterCell.velocity = 200;
emitterCell.velocityRange = 50;
emitterCell.yAcceleration = 250;
emitterCell.contents = (id)[[UIImage imageNamed:#"particle.png"] CGImage];
emitterLayer.emitterCells = [NSArray arrayWithObject:emitterCell];
[parentView.layer addSublayer:emitterLayer];
Everything works well but now I want to pause or suspend the animation, so the particles "freeze". Can this be done?

I think pause the layer will work,
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}

Related

Can SKEmitterNode particles be rotated around their X and Y axes? [duplicate]

I'm trying to reproduce pieces of small paper falling from top effect, using CAEmitterLayer & CAEmitterCell.
So far, I got the 2D animation of it, But I'm having difficulty to make each cell to rotate when falling.
How to I apply random rotation on each particle? I tried with 3D Transform with no success so far.
This is what I got:
-(void) configureEmitterLayer {
self.emitterLayer = [CAEmitterLayer layer];
self.emitterLayer.emitterPosition = CGPointMake(self.backgroundContainer.bounds.size.width /2, 0);
self.emitterLayer.emitterZPosition = 10;
self.emitterLayer.emitterSize = self.backgroundContainer.bounds.size;
self.emitterLayer.emitterShape = kCAEmitterLayerLine;
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
emitterCell.contents = (__bridge id)([UIImage imageWithColor:[UIColor whiteColor]].CGImage);
emitterCell.lifetime = CGFLOAT_MAX;
emitterCell.lifetimeRange = 4.0;
emitterCell.birthRate = 2.5;
emitterCell.color = [[UIColor colorWithRed:1.0f green:1.0 blue:1.0 alpha:1.0] CGColor];
emitterCell.redRange = 1.0;
emitterCell.blueRange = 1.0;
emitterCell.greenRange = 1.0;
emitterCell.alphaRange = 0.3;
emitterCell.velocity = 10;
emitterCell.velocityRange = 3;
emitterCell.emissionRange = (CGFloat) M_PI_2;
emitterCell.emissionLongitude = (CGFloat) M_PI;
emitterCell.yAcceleration = 1;
emitterCell.zAcceleration = 4;
emitterCell.spinRange = 2.0;
emitterCell.scale = 7.0;
emitterCell.scaleRange = 4.0;
self.emitterLayer.emitterCells = [NSArray arrayWithObject:emitterCell];
[self.backgroundContainer.layer addSublayer:self.emitterLayer];
}
This library doesn't use the emitter framework but is worth looking at for inspiration. UIDynamics is attached to individual objects to achieve the desired effect.
iOS confetti example

How do I restart a CALayer animation going on?

Apple mentions these two methods for pausing and resuming a CALayer animation going on
-(void)pauseLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
but how do I restart the animation?
this other SO question has nothing to do with what I need.
I have adopted code from blog in ViewController. Take a look at method [resetEmitterLayer:]. In your case all you need to do to reset animation is as follow:
Remove emitter layer from super layer.
Recreate emitter layer.
Add new emitter layer to the layer tree.
See ViewController implementation below
#import "EmitterViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface EmitterViewController ()
#property (nonatomic, strong) CAEmitterLayer *emitterLayer;
#end
#implementation EmitterViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.emitterLayer = [self createEmitterLayer];
[self.view.layer addSublayer:self.emitterLayer];
}
-(CAEmitterLayer *)createEmitterLayer {
CAEmitterLayer *emitterLayer = [CAEmitterLayer layer];
emitterLayer.emitterPosition = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.origin.y);
emitterLayer.emitterZPosition = 10;
emitterLayer.emitterSize = CGSizeMake(self.view.bounds.size.width, 0);
emitterLayer.emitterShape = kCAEmitterLayerSphere;
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
emitterCell.scale = 0.1;
emitterCell.scaleRange = 0.2;
emitterCell.emissionRange = (CGFloat)M_PI_2;
emitterCell.lifetime = 5.0;
emitterCell.birthRate = 10;
emitterCell.velocity = 200;
emitterCell.velocityRange = 50;
emitterCell.yAcceleration = 250;
emitterCell.contents = (id)[[UIImage imageNamed:#"WaterDrop.png"] CGImage];
emitterLayer.emitterCells = [NSArray arrayWithObject:emitterCell];
return emitterLayer;
}
-(IBAction)pauseEmitterLayer:(id)sender
{
CFTimeInterval pausedTime = [self.emitterLayer convertTime:CACurrentMediaTime() fromLayer:nil];
self.emitterLayer.speed = 0.0;
self.emitterLayer.timeOffset = pausedTime;
}
-(IBAction)resumeEmitterLayer:(id)sender
{
CFTimeInterval pausedTime = [self.emitterLayer timeOffset];
self.emitterLayer.speed = 1.0;
self.emitterLayer.timeOffset = 0.0;
self.emitterLayer.beginTime = 0.0;
CFTimeInterval timeSincePause = [self.emitterLayer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
self.emitterLayer.beginTime = timeSincePause;
}
-(IBAction)resetEmitterLayer:(id)sender
{
[self.emitterLayer removeFromSuperlayer];
self.emitterLayer = [self createEmitterLayer];
[self.view.layer addSublayer:self.emitterLayer];
}
#end

CAEmitterLayer animation that leaves accurate trail along the path

I need to leave a trail with UIView that is animated with CAKeyframeAnimation
Ball * ball = [[Ball alloc]init];
// customized the ball
CGMutablePathRef path = CGPathCreateMutable();
// filling in the path from points.
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
anim.path = path;
anim.rotationMode = kCAAnimationRotateAuto;
anim.repeatCount = HUGE_VALF;
anim.duration = 1.2;
anim.cumulative = YES;
anim.additive = YES;
[ball.layer addAnimation:anim forKey:#"fly"];
Now the Ball.m will have the following Emitter layer:
#implementation TennisBall{
__weak CAEmitterLayer *emitterLayer;
}
+ (Class)layerClass
{
return [CAEmitterLayer class];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupLayer];
emitterLayer = [CAEmitterLayer layer];
emitterLayer.frame = self.bounds;
emitterLayer.emitterPosition = CGPointMake(160, 240);
emitterLayer.emitterSize = CGSizeMake(10, 10);
emitterLayer.renderMode = kCAEmitterLayerAdditive;
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell];
emitterCell.birthRate = 1;
emitterCell.lifetime = 10.0;
emitterCell.lifetimeRange = 0.5;
emitterCell.velocity = 20;
emitterCell.velocityRange = 10;
emitterCell.emissionRange = 0;
emitterCell.scaleSpeed = 0.3;
emitterCell.spin = 0;
emitterCell.color = [[UIColor colorWithRed:0.8 green:0.4 blue:0.2 alpha:0.1]
CGColor];
emitterCell.contents = (id)[[UIImage imageNamed:#"first.png"] CGImage];
[emitterCell setName:#"fire"];
emitterLayer.emitterCells = [NSArray arrayWithObject:emitterCell];
[self.layer addSublayer:emitterLayer];
}
return self;
}
I just need the ball to leave a trail that repeats the path that the ball travels. How do I achieve that?
To make sure the emitter position is correct it the ball layer,
You need to make sure emitterPosition same as its anchorPoint.
For example, if anchorPoint is (0,0), then emitterPosition is (0,0).
If anchorPoint is (0.5,0.5), and size is (0,0,300,300) then emitterPosition is (150,150)

How to animate an image in backward using CAKeyFrameAnimation

I'm new in iOS development. I'm creating a Keyframe animation for rotating the image.The image was successfully rotated in forward.I want to rotate the image in full and full backward.
This is my code.
UIImageView *tempView = [[UIImageView alloc] initWithFrame:CGRectMake(28,158,133,133)];
tempView.image = [UIImage imageNamed:#"1_03.png"];
[self.view addSubview:tempView];
const NSUInteger rotations = 1;
const NSTimeInterval duration = 4.0f;
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"transform.rotation"];
CGFloat touchUpStartAngle = 0;
CGFloat touchUpEndAngle = (M_PI);
CGFloat angularVelocity = (((2 * M_PI) * rotations) + M_PI) / duration;
anim.values = #[#(touchUpStartAngle), #(touchUpStartAngle + angularVelocity * duration)];
anim.duration = duration;
anim.delegate = self;
anim.repeatCount = INFINITY;
[tempView.layer addAnimation:anim forKey:#"animation"];
tempView.transform = CGAffineTransformMakeRotation(touchUpStartAngle + (touchUpEndAngle));
How to do this.
Try this.
UIImageView *tempView = [[UIImageView alloc] initWithFrame:CGRectMake(28,158,133,133)];
tempView.image = [UIImage imageNamed:#"1_03.png"];
[self.view addSubview:tempView];
const NSUInteger rotations = 1;
const NSTimeInterval duration = 4.0f;
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"transform.rotation"];
CGFloat touchUpStartAngle = 0;
CGFloat touchUpEndAngle = (M_PI);
CGFloat angularVelocity = (((2 * M_PI) * rotations) + M_PI) / duration;
anim.values = #[#(touchUpStartAngle), #(touchUpStartAngle - angularVelocity * duration)];
anim.duration = duration;
anim.delegate = self;
anim.repeatCount = INFINITY;
[tempView.layer addAnimation:anim forKey:#"animation"];
tempView.transform = CGAffineTransformMakeRotation(touchUpStartAngle + (touchUpEndAngle));
Try this
CGFloat touchUpStartAngle = 0;
CGFloat touchUpEndAngle = (M_PI);
CGFloat angularVelocity = (((2 * M_PI) * rotations) + M_PI) / duration;
anim.values = #[#(touchUpStartAngle), #(touchUpStartAngle - angularVelocity * duration)];

iOS CAEmitterLayer how to show animation on uiimageview

I am following this tutorial "http://www.raywenderlich.com/6063/uikit-particle-systems-in-ios-5-tutorial". everything works but I want that effect to go on my image view.
please help where should I make changes
this is code I have in my view controller on which I am showing animation
-(IBAction)ClickOn:(id)sender
{
[fireView startAnimation];
[fireView setIsEmitting:YES];
[self.view bringSubviewToFront:fireView];
[self.view sendSubviewToBack:sample];
}
and this is code in library view class
-(void)startAnimation
{
NSLog(#"awakeFromNib");
//set ref to the layer
fireEmitter = (CAEmitterLayer*)self.layer; //2
//configure the emitter layer
fireEmitter.emitterSize = CGSizeMake(20, 20);
CAEmitterCell* fire = [CAEmitterCell emitterCell];
fire.birthRate = 0;
fire.lifetime = 2.0;
fire.lifetimeRange = 1.5;
fire.color = [[UIColor colorWithRed:236 green:237 blue:237 alpha:0.1] CGColor];
fire.contents = (id)[[UIImage imageNamed:#"Particles_fire.png"] CGImage];
[fire setName:#"fire"];
fire.yAcceleration =
fire.velocity = 0.1;
fire.velocityRange = 80;
fire.emissionRange = 80;
fire.scale = 1.0;
fire.scaleSpeed = 0.1;
fire.spin = 40.5;
CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:#"emitterPosition"];
ba.fromValue = [NSValue valueWithCGPoint:CGPointMake(150, 400)];
ba.toValue = [NSValue valueWithCGPoint:CGPointMake(300,0)];
ba.duration = 6;
ba.autoreverses = NO;
[fireEmitter addAnimation:ba forKey:nil];
fireEmitter.renderMode = kCAEmitterLayerPoints;
//add the cell to the layer and we're done
fireEmitter.emitterCells = [NSArray arrayWithObject:fire];
fireEmitter.zPosition = 400.0;
}
basically i just want animation to go above uiimageview or uiview, currently it is going behind it

Resources