Question

I'm trying to add a simple particle effect overlay to one of my UIViewController instances. I've followed a couple of tutorials I found, but neither of them deal with view controllers and their storyboards are just a view out on its own with no controller, which is confusing.

Here's my code, I'm just trying to figure out why I can't see the particle effects. What am I missing? The view itself is definitely there and added (if I change its color or something I can see it), it's just empty, and isn't showing any particle effects. The image file referenced is definitely in the project and target, so what else have I done wrong here? Do I need to add the CAEmitterLayer to rainView somehow? The tutorials didn't offer any help on this part!

RainfallOverlay.h

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface RainfallOverlay : UIView {
    CAEmitterLayer *rainEmitter;
}

@end

RainfallOverlay.m

#import "RainfallOverlay.h"

@implementation RainfallOverlay

- (void) awakeFromNib
{
    rainEmitter = (CAEmitterLayer *) self.layer;
    rainEmitter.emitterPosition = CGPointMake(160, 100);
    rainEmitter.emitterSize = CGSizeMake(10, 10);
    rainEmitter.renderMode = kCAEmitterLayerAdditive;

    CAEmitterCell *rain = [CAEmitterCell emitterCell];
    rain.birthRate = 200;
    rain.lifetime = 2.0;
    rain.lifetimeRange = 1.5;
    rain.color = [[UIColor colorWithRed: 0.2 green: 0.4 blue: 0.8 alpha: 0.1] CGColor];
    rain.contents = (id) [[UIImage imageNamed: @"Particles_rain.png"] CGImage];
    rain.name = @"rain";
    rain.velocity = 150;
    rain.velocityRange = 100;
    rain.emissionRange = M_PI_2;
    rain.emissionLongitude = 0.025 * 180 / M_PI;
    rain.scaleSpeed = 0;
    rain.spin = 0.5;

    rainEmitter.emitterCells = [NSArray arrayWithObject: rain];
}

@end

ViewController.m viewDidLoad

RainfallOverlay *rainView = [[RainfallOverlay alloc] initWithFrame: CGRectMake(0, 0, 320, 250)];
[rainView setUserInteractionEnabled: NO];
[self.view bringSubviewToFront: rainView];
[self.view addSubview: rainView];
Was it helpful?

Solution

There are 2 problems:

  • awakeFromNib would only be called if the view is loaded from a nib file. In your case, you have to implement initWithFrame.
  • You have to override layerClass to that self.layer returns a CAEmitterLayer. Just casting the layer to CAEmitterLayer does not work.

So your RainfallOverlay implementation should look like this:

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

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        rainEmitter = (CAEmitterLayer *) self.layer;

        // ... remaining setup
    }
    return self;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top