1

I want to make Confetti effect after user guess correctly, I searched the web and found something that looks really good, but it only have the .m file, I don't have any idea what to do with the header file.

This is the link to the page with the Confetti effect link

This is the .m file itself, I get an error on those lines:

if ((self = [super initWithFrame:frame])) {
    self.userInteractionEnabled = NO;
    self.backgroundColor = [UIColor clearColor];
    _confettiEmitter = (CAEmitterLayer*)self.layer;

Why is the errors appears?

//
// Created by tdimson on 8/15/12.

#import <QuartzCore/QuartzCore.h>
#import "SFSConfettiScreen.h"


@implementation SFSConfettiScreen {
    __weak CAEmitterLayer *_confettiEmitter;
    CGFloat _decayAmount;
}

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        self.userInteractionEnabled = NO;
        self.backgroundColor = [UIColor clearColor];
        _confettiEmitter = (CAEmitterLayer*)self.layer;
        _confettiEmitter.emitterPosition = CGPointMake(self.bounds.size.width /2, 0);
        _confettiEmitter.emitterSize = self.bounds.size;
        _confettiEmitter.emitterShape = kCAEmitterLayerLine;

        CAEmitterCell *confetti = [CAEmitterCell emitterCell];
        confetti.contents = (__bridge id)[[UIImage imageNamed:@"Confetti.png"] CGImage];
        confetti.name = @"confetti";
        confetti.birthRate = 150;
        confetti.lifetime = 5.0;
        confetti.color = [[UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0] CGColor];
        confetti.redRange = 0.8;
        confetti.blueRange = 0.8;
        confetti.greenRange = 0.8;

        confetti.velocity = 250;
        confetti.velocityRange = 50;
        confetti.emissionRange = (CGFloat) M_PI_2;
        confetti.emissionLongitude = (CGFloat) M_PI;
        confetti.yAcceleration = 150;
        confetti.scale = 1.0;
        confetti.scaleRange = 0.2;
        confetti.spinRange = 10.0;
        _confettiEmitter.emitterCells = [NSArray arrayWithObject:confetti];
    }

    return self;
}

+ (Class) layerClass {
    return [CAEmitterLayer class];
}

static NSTimeInterval const kDecayStepInterval = 0.1;
- (void) decayStep {
    _confettiEmitter.birthRate -=_decayAmount;
    if (_confettiEmitter.birthRate < 0) {
        _confettiEmitter.birthRate = 0;
    } else {
        [self performSelector:@selector(decayStep) withObject:nil afterDelay:kDecayStepInterval];
    }
}

- (void) decayOverTime:(NSTimeInterval)interval {
    _decayAmount = (CGFloat) (_confettiEmitter.birthRate /  (interval / kDecayStepInterval));
    [self decayStep];
}

- (void) stopEmitting {
    _confettiEmitter.birthRate = 0.0;
}

@end
ytpm
  • 4,962
  • 6
  • 56
  • 113

1 Answers1

1

Should be pretty straightforward to reverse-engineer this. It's obviously a UIView subclass, so something like this should suffice, and in modern Objective-C, you don't even need to declare the instance variables in the implementation file.

@interface SFSConfettiScreen : UIView

@property(nonatomic, weak) CAEmitterLayer *confettiEmitter;
@property(nonatomic, assign) CGFloat decayAmount;

@end

This should work if your version of Xcode is 4.4 or newer, as it should be. Otherwise, leave the implementation as-is and remove the @property declarations, leaving an empty interface declaration. That should also work; I just prefer properties to ivars.

warrenm
  • 31,094
  • 6
  • 92
  • 116
  • First of all, thank you very much for the detailed answer. I have an error on the second property of the CGFloat, it says: `Property with 'retain (or strong)' attribute must be of object type`, what does it means? – ytpm Dec 01 '12 at 21:35
  • 1
    That was a silly error on my part. Because `CGFloat` is a primitive type, we should use `assign` there. See the corrected code above. – warrenm Dec 01 '12 at 21:38
  • Just one last question if I may, you've already helped me too much. How can I implement this code on my view? Thanks again. – ytpm Dec 01 '12 at 21:43
  • 1
    Having not read the whole source article, I'm not qualified to say, but you could probably create one of these views that's the same size as the screen and add it as a subview to the root view of an existing view controller. That should cause the confetti particles to be composited on top of whatever content is being shown in the parent view. – warrenm Dec 01 '12 at 21:45