3

I have a game similar to fruit ninja using Swift -> SpriteKit. Everything is working fine on iOS 8 but on iOS 9 SKEmitterNode is having a bit strange behavior. This is what I get for my blade effect on both:

enter image description here

 func emitterNodeWithColor(color:UIColor)->SKEmitterNode {
let emitterNode:SKEmitterNode = SKEmitterNode()
emitterNode.particleTexture = SKTexture(imageNamed: "spark.png")
emitterNode.particleBirthRate = 3000
emitterNode.particleLifetime = 0.2
emitterNode.particleLifetimeRange = 0

emitterNode.particlePositionRange = CGVectorMake(0.0, 0.0)

emitterNode.particleSpeed = 0.0
emitterNode.particleSpeedRange = 0.0

emitterNode.particleAlpha = 0.8
emitterNode.particleAlphaRange = 0.2
emitterNode.particleAlphaSpeed = -0.45

emitterNode.particleScale = 0.5
emitterNode.particleScaleRange = 0.001
emitterNode.particleScaleSpeed = -1

emitterNode.particleRotation = 0
emitterNode.particleRotationRange = 0
emitterNode.particleRotationSpeed = 0

emitterNode.particleColorBlendFactor = 1
emitterNode.particleColorBlendFactorRange = 0
emitterNode.particleColorBlendFactorSpeed = 0

emitterNode.particleColor = color
emitterNode.particleBlendMode = SKBlendMode.Add

return emitterNode

}

let emitter:SKEmitterNode = emitterNodeWithColor(color)
emitter.targetNode = target
emitter.zPosition = 0
tip.addChild(emitter)

This is the method I am using with all the options. It is the same for both but the result is different. Any ideas how can I make the effect in iOS 9 to be the same as iOS 8 ?

Viktor Todorov
  • 380
  • 3
  • 15

1 Answers1

2

I'm facing the exact same issue in my project. The emitter's performance is low in iOS9 (Metal version not finished?), so Apple shut off the interpolation of the drawing to get back the performance a little (The drawing rate is limited to 60 fps, anything between two frames is not rendered). My solution is to implement the tail myself, which is simple:

class TailNode: SKSpriteNode {

var tailTexture: SKTexture!
var tailSize: CGSize! = CGSizeMake(30, 30)
var tailColor: SKColor!
var tailBlendMode: SKBlendMode!
var initialAlpha: CGFloat = 0.6
var initialScale: CGFloat = 0
var finalScale: CGFloat = 1
var particleLife: NSTimeInterval = 0.1

var running: Bool = false
var particleAction: SKAction!
var lastParticle: SKSpriteNode?

var battleScene: BattleScene {
    return self.scene as! BattleScene
}

convenience init(tailTexture: SKTexture, tailSize: CGSize, tailColor: SKColor, tailBlendMode: SKBlendMode, initialAlpha: CGFloat, initialScale: CGFloat, finalScale: CGFloat, particleLife: NSTimeInterval) {
    self.init(texture: nil, color: SKColor.whiteColor(), size: CGSize(width: 0, height: 0))
    self.tailTexture = tailTexture
    self.tailSize = tailSize
    self.tailColor = tailColor
    self.tailBlendMode = tailBlendMode
    self.initialAlpha = initialAlpha
    self.initialScale = initialScale
    self.finalScale = finalScale
    self.particleLife = particleLife

    let fadeAction = SKAction.fadeAlphaTo(0, duration: particleLife)
    let scaleAction = SKAction.scaleTo(finalScale, duration: particleLife)
    let removeAction = SKAction.removeFromParent()
    self.particleAction = SKAction.sequence([SKAction.group([fadeAction, scaleAction]), removeAction])
}

func updateWithTimeSinceLastUpdate(interval: NSTimeInterval) {
    if running {
        let particlePosition = battleScene.convertPoint(battleScene.convertPoint(self.position, fromNode: self.parent!),
                                                    toNode:battleScene.worldLayers[.UnderCharacter]!)
        if lastParticle == nil || lastParticle!.parent == nil {
            lastParticle = nil
        } else {
            let lastPosition = lastParticle!.position
            let x = lastPosition.x + (particlePosition.x - lastPosition.x)*0.5
            let y = lastPosition.y + (particlePosition.y - lastPosition.y)*0.5
            newParticleAtPosition(CGPointMake(x, y), withDelay: interval*0.5)
        }
        lastParticle = newParticleAtPosition(particlePosition, withDelay: interval)
    }
}

func newParticleAtPosition(position: CGPoint, withDelay delay: NSTimeInterval) -> SKSpriteNode {
    let myParticle = SKSpriteNode(texture: tailTexture, color: tailColor, size: tailSize)
    myParticle.colorBlendFactor = 1
    myParticle.blendMode = tailBlendMode
    myParticle.alpha = initialAlpha
    myParticle.setScale(initialScale)
    myParticle.position = position
    battleScene.addNode(myParticle, atWorldLayer: .UnderCharacter)
    myParticle.runAction(SKAction.sequence([SKAction.waitForDuration(delay), particleAction]))
    return myParticle
}

}

Jian Shen
  • 36
  • 3
  • I have tried following this, and have slightly modified it for my game, but the following line will not work `GameScene.convertPoint(GameScene.convertPoint(self.position, fromNode: self.parent!), toNode:GameScene.worldLayers[.UnderCharacter]!)` – Neel Sarwal Nov 03 '15 at 20:13