How to Add Particle Effects to an iOS App That Is Not a Game Using iOS 7 Spritekit Particle

How to add particle effects to an iOS App that is not a game using iOS 7 SpriteKit Particle?

Create a SKScene in your UIView to add a SKEmitterNode particle effect.

One way of doing this:

1.In storyboard (or programatically if you prefer) add a View object on top of the existing View and resize it to your needs.

2.Change the class of the new view to SKView

3.In your view controller .h file create a property for the SKView:

@property IBOutlet SKView *skView;

4.Link the SKView on your storyboard to the skView property.

5.Create a new class, subclassing SKScene. MyScene.h will look like:

#import <SpriteKit/SpriteKit.h>
@interface MyScene : SKScene
@end

MyScene.m below contains code to create a particle effect whenever and wherever the SKView is touched.

#import "MyScene.h"

@implementation MyScene

-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */

self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
myLabel.text = @"Hello, World!";
myLabel.fontSize = 30;
myLabel.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));

[self addChild:myLabel];
}
return self;
}

//particle explosion - uses MyParticle.sks
- (SKEmitterNode *) newExplosion: (float)posX : (float) posy
{
SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:@"MyParticle" ofType:@"sks"]];
emitter.position = CGPointMake(posX,posy);
emitter.name = @"explosion";
emitter.targetNode = self.scene;
emitter.numParticlesToEmit = 1000;
emitter.zPosition=2.0;
return emitter;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */

for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
//add effect at touch location
[self addChild:[self newExplosion:location.x : location.y]];
}
}

-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
}

@end

6.In your main view controller, include your scene class:

#import "MyScene.h"

and add code to viewDidLoad to initialise the SKView:

- (void)viewDidLoad
{
[super viewDidLoad];

// Configure the SKView
SKView * skView = _skView;
skView.showsFPS = YES;
skView.showsNodeCount = YES;

// Create and configure the scene.
SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;

// Present the scene.
[skView presentScene:scene];
}

You should then have a working SKScene within your main UIView.

How to add particle system to ios app without black background

Sprite Kit views cannot be made transparent. But Sprite Kit isn't the only way to get particle effects in iOS. Look into CAEmitterLayer — that's more appropriate for mixing with UIKit.

Making a particle follow a path in spriteKit

You sent the particle emitter to follow the path. If you want individual particles to run an action, use the emitter's particleAction property:

myParticle.particleAction = forever;

Should I consider SpriteKit for a non-game iOS App?

Absolutely. Sprite Kit was obviously created with games in mind, but there is no reason you can't use it for regular applications that have similar needs.

Custom Particle System for iOS

This can give you a basic idea what I was meant in my comments. But keep in mind that it is untested and I am not sure how it will behave if frame rate drops occur.

This example creates 5 particles per second, add them sequentially (in counterclockwise direction) along the perimeter of a given circle. Each particle will have different predefined color. You can play with Settings struct properties to change the particle spawning speed or to increase or decrease number of particles to emit.

Pretty much everything is commented, so I guess you will be fine:

Swift 2

import SpriteKit

struct Settings {

static var numberOfParticles = 30
static var particleBirthRate:CGFloat = 5 //Means 5 particles per second, 0.2 means one particle in 5 seconds etc.
}

class GameScene: SKScene {

var positions = [CGPoint]()
var colors = [SKColor]()

var emitterNode:SKEmitterNode?

var currentPosition = 0

override func didMoveToView(view: SKView) {

backgroundColor = .blackColor()


emitterNode = SKEmitterNode(fileNamed: "rain.sks")

if let emitter = emitterNode {

emitter.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame))
emitter.particleBirthRate = Settings.particleBirthRate
addChild(emitter)


let radius = 50.0
let center = CGPointZero

for var i = 0; i <= Settings.numberOfParticles; i++ {

//Randomize color
colors.append(SKColor(red: 0.78, green: CGFloat(i*8)/255.0, blue: 0.38, alpha: 1))

//Create some points on a perimeter of a given circle (radius = 40)
let angle = Double(i) * 2.0 * M_PI / Double(Settings.numberOfParticles)
let x = radius * cos(angle)
let y = radius * sin(angle)


let currentParticlePosition = CGPointMake(CGFloat(x) + center.x, CGFloat(y) + center.y)

positions.append(currentParticlePosition)

if i == 1 {
/*
Set start position for the first particle.
particlePosition is starting position for each particle in the emitter's coordinate space. Defaults to (0.0, 0,0).
*/
emitter.particlePosition = positions[0]
emitter.particleColor = colors[0]

self.currentPosition++
}

}

// Added just for debugging purposes to show positions for every particle.
for particlePosition in positions {

let sprite = SKSpriteNode(color: SKColor.orangeColor(), size: CGSize(width: 1, height: 1))
sprite.position = convertPoint(particlePosition, fromNode:emitter)
sprite.zPosition = 2
addChild(sprite)
}


let block = SKAction.runBlock({

// Prevent strong reference cycles.
[unowned self] in

if self.currentPosition < self.positions.count {

// Set color for the next particle
emitter.particleColor = self.colors[self.currentPosition]

// Set position for the next particle. Keep in mind that particlePosition is a point in the emitter's coordinate space.
emitter.particlePosition = self.positions[self.currentPosition++]

}else {

//Stop the action
self.removeActionForKey("emitting")
emitter.particleBirthRate = 0
}

})


// particleBirthRate is a rate at which new particles are generated, in particles per second. Defaults to 0.0.

let rate = NSTimeInterval(CGFloat(1.0) / Settings.particleBirthRate)

let sequence = SKAction.sequence([SKAction.waitForDuration(rate), block])

let repeatAction = SKAction.repeatActionForever(sequence)


runAction(repeatAction, withKey: "emitting")
}

}
}

Swift 3.1

import SpriteKit

struct Settings {

static var numberOfParticles = 30
static var particleBirthRate:CGFloat = 5 //Means 5 particles per second, 0.2 means one particle in 5 seconds etc.
}

class GameScene: SKScene {

var positions = [CGPoint]()
var colors = [SKColor]()

var emitterNode: SKEmitterNode?

var currentPosition = 0

override func didMove(to view: SKView) {

backgroundColor = SKColor.black

emitterNode = SKEmitterNode(fileNamed: "rain.sks")

if let emitter = emitterNode {

emitter.position = CGPoint(x: frame.midX, y: frame.midY)
emitter.particleBirthRate = Settings.particleBirthRate
addChild(emitter)

let radius = 50.0
let center = CGPoint.zero

for var i in 0...Settings.numberOfParticles {

//Randomize color
colors.append(SKColor(red: 0.78, green: CGFloat(i * 8) / 255.0, blue: 0.38, alpha: 1))

//Create some points on a perimeter of a given circle (radius = 40)
let angle = Double(i) * 2.0 * Double.pi / Double(Settings.numberOfParticles)
let x = radius * cos(angle)
let y = radius * sin(angle)

let currentParticlePosition = CGPoint.init(x: CGFloat(x) + center.x, y: CGFloat(y) + center.y)

positions.append(currentParticlePosition)

if i == 1 {
/*
Set start position for the first particle.
particlePosition is starting position for each particle in the emitter's coordinate space. Defaults to (0.0, 0,0).
*/
emitter.particlePosition = positions[0]
emitter.particleColor = colors[0]

self.currentPosition += 1
}

}

// Added just for debugging purposes to show positions for every particle.
for particlePosition in positions {

let sprite = SKSpriteNode(color: SKColor.orange, size: CGSize(width: 1, height: 1))
sprite.position = convert(particlePosition, from: emitter)
sprite.zPosition = 2
addChild(sprite)
}

let block = SKAction.run({

// Prevent strong reference cycles.
[unowned self] in

if self.currentPosition < self.positions.count {

// Set color for the next particle
emitter.particleColor = self.colors[self.currentPosition]

// Set position for the next particle. Keep in mind that particlePosition is a point in the emitter's coordinate space.
emitter.particlePosition = self.positions[self.currentPosition]

self.currentPosition += 1

} else {

//Stop the action
self.removeAction(forKey: "emitting")
emitter.particleBirthRate = 0
}

})

// particleBirthRate is a rate at which new particles are generated, in particles per second. Defaults to 0.0.

let rate = TimeInterval(CGFloat(1.0) / Settings.particleBirthRate)

let sequence = SKAction.sequence([SKAction.wait(forDuration: rate), block])

let repeatAction = SKAction.repeatForever(sequence)

run(repeatAction, withKey: "emitting")
}

}
}

Orange dots are added just for debugging purposes and you can remove that part if you like.

Personally I would say that you are overthinking this, but I might be wrong because there is no clear description of what you are trying to make and how to use it. Keep in mind that SpriteKit can render a bunch of sprites in a single draw call in very performant way. Same goes with SKEmitterNode if used sparingly. Also, don't underestimate SKEmitterNode... It is very configurable actually.

Here is the setup of Particle Emitter Editor:

Particle Emitter Editor

Anyways, here is the final result:

emitter

Note that nodes count comes from an orange SKSpriteNodes used for debugging. If you remove them, you will see that there is only one node added to the scene (emitter node).

With Swift and SpriteKit - emit particles trail following the swipe?

Here's simple code for swift, you'll need to add an sks named "MyParticle".

Right-click on the left sidebar inside xcode, pick new file, pick Resource, Sprite Kit Particle File etc.

I tested it with Fire.

import SpriteKit
class Game: SKScene{

var pathEmitter = SKEmitterNode(fileNamed: "MyParticle")
override func didMoveToView(view: SKView)
{
pathEmitter.position = CGPointMake(-100, -100)
self.addChild(pathEmitter)
pathEmitter.targetNode = self
}

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {

let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
pathEmitter.position = touchLocation
}

override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {

let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
pathEmitter.position = touchLocation
}
}


Related Topics



Leave a reply



Submit