2016-03-27 13 views
0

Was ich tun möchte, scheint mir sehr einfach zu sein, aber ich kann keinen Weg finden es zu implementieren, da ich ziemlich neu in iOS bin.Swift: Animate SKSpriteNode Gradient

Ich möchte meinen Hintergrund so gut wie einen Farbverlauf haben, der die Farben durch Ein- und Ausblenden sehr langsam verändert.

Ich habe das auf Github gefunden und es verwendet, um zwei Farbverlaufsknoten mit verschiedenen Farben zu erstellen, das einzige Problem ist, dass ich nicht scheinen kann, Alpha zu animieren oder es in irgendeiner Weise ein- und ausblenden. https://github.com/braindrizzlestudio/BDGradientNode Hier ist, was ich getan habe:

//Blueish 
    let color1 = UIColor(red: 0.965, green: 0.929, blue: 0.667, alpha: 1) 
    let color2 = UIColor(red: 0.565, green: 0.71, blue: 0.588, alpha: 1) 
    let color3 = UIColor(red: 0.259, green: 0.541, blue: 0.529, alpha: 1) 
    let colors = [color1, color2, color3] 

    //Redish 
    let color4 = UIColor(red: 1, green: 0.518, blue: 0.769, alpha: 1) 
    let color5 = UIColor(red: 0.859, green: 0.22, blue: 0.541, alpha: 1) 
    let color6 = UIColor(red: 0.737, green: 0, blue: 0.314, alpha: 1) 
    let colors2 = [color4, color5, color6] 

    let blending : Float = 0.3 

    let location1 : CGFloat = 0.5 
    let locations : [CGFloat] = [location1] 

    let startPoint = CGPoint(x: 0.3, y: 0.0) 
    let endPoint = CGPoint(x: 0.6, y: 0.8) 

    let size = CGSize(width: self.size.width, height: self.size.height) 

    let texture = SKTexture(imageNamed: "White Background") 


    myGradientNode = BDGradientNode(linearGradientWithTexture: texture, colors: colors, locations: nil, startPoint: startPoint, endPoint: endPoint, blending: blending, keepTextureShape: true, size: size) 

    myGradientNode2 = BDGradientNode(linearGradientWithTexture: texture, colors: colors2, locations: nil, startPoint: startPoint, endPoint: endPoint, blending: blending, keepTextureShape: true, size: size) 
    myGradientNode2?.blending = 0 

    self.addChild(myGradientNode2!) 
    self.addChild(myGradientNode!) 

Ich fühle mich wie es ein einfacher Weg ist, vielleicht nicht verwenden. Sie sehen das jetzt in vielen Spiele-Apps und es würde so viel helfen, wenn mir jemand dabei helfen könnte, dieses atemberaubende Design zu erreichen!

Antwort

1

Hier ist eine mögliche Komplettlösung (in Swift 2.2), die Sie nach Herzenslust optimieren können (einschließlich Fehlerbehandlung, die für Ihre App sinnvoll ist). Ich werde den Code in umgekehrter Reihenfolge auslegen, mit dem Ziel, ausgehend der Lage zu schreiben:

// assuming: 
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5) 

if let bg = HorizontalGradientNode(
    size: scene.size, 
    fadingFrom: [.AliceBlue, .BurlyWood], 
    to: [.AliceBlue, .CornflowerBlue], 
    wait: 1, 
    duration: 2) 
{ 
    scene.addChild(bg) 
} 

Dieser einen Knoten zu der Szene hinzufügen wird Einkapseln zwei Kinder Gradienten Sprite Knoten, die oben von denen verblassen für immer und ewig. Die HorizontalGradientNode.init nimmt zwei Arrays von CGColor. Sie können zwei oder mehr Farben jedes enthalten! Die genannten CGColor s (AliceBlue, CornflowerBlue, etc.) kann auf die folgende Art und Weise konstruiert werden:

class HorizontalGradientNode : SKNode { 

    init?(size: CGSize, fadingFrom colors1: [CGColor], to colors2: [CGColor], wait: NSTimeInterval, duration: NSTimeInterval) { 
     guard 
      let grad1 = CGImage.withHorizontalGradient(size: size, colors: colors1), 
      let grad2 = CGImage.withHorizontalGradient(size: size, colors: colors2) 
      else 
     { 
      return nil 
     } 
     let bg1 = SKSpriteNode(texture: SKTexture(CGImage: grad1)) 
     let bg2 = SKSpriteNode(texture: SKTexture(CGImage: grad2)) 
     bg2.alpha = 0 

     super.init() 
     addChild(bg1) 
     addChild(bg2) 

     bg2.runAction(
      .repeatActionForever(
       .sequence(
        [ 
         .waitForDuration(wait), 
         .fadeInWithDuration(duration), 
         .waitForDuration(wait), 
         .fadeOutWithDuration(duration) 
        ] 
       ) 
      ) 
     ) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 
} 

werden diese CGImage.withHorizontalGradient(size:, colors:) umgesetzt könnte als:

public extension CGColor { 

    public static func withHex(hex: Int, alpha: CGFloat = 1) -> CGColor { 
     let x = max(0, min(hex, 0xffffff)) 
     let r = CGFloat((x & 0xff0000) >> 16) /0xff 
     let g = CGFloat((x & 0x00ff00) >> 8) /0xff 
     let b = CGFloat(x & 0x0000ff)  /0xff 
     return CGColorCreateGenericRGB(r, g, b, alpha) 
    } 

    public static var AliceBlue: CGColor { return .withHex(0xF0F8FF) } 
    public static var BurlyWood: CGColor { return .withHex(0xDEB887) } 
    public static var CornflowerBlue: CGColor { return .withHex(0x6495ED) } 
    // see named colours at: http://www.w3schools.com/colors/colors_names.asp 
} 

Die einfachste Version von HorizontalGradientNode etwas sein würde, folgt:

public extension CGImage { 

    public static func withHorizontalGradient(size size: CGSize, colors: [CGColor]) -> CGImage? { 
     guard colors.count >= 2 else { return nil } 
     let locations: [CGFloat] = colors.indices.map{ 
      CGFloat($0)/CGFloat(colors.count - 1) 
     } 
     guard let gradient = CGGradientCreateWithColors(nil, colors, locations) else { 
      return nil 
     } 
     let start = CGPoint(x: size.width/2, y: size.height) 
     let end = CGPoint(x: size.width/2, y: 0) 
     return CGContext.rgb(size)? 
      .draw(linearGradient: gradient, start: start, end: end) 
      .image 
    } 
} 

Verwenden von Punkt Syntaxerweiterungen von CGContext like:

public extension CGContext { 

    public static func rgb(size: CGSize) -> CGContext? { 
     let sp = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB) 
     let bi = CGImageAlphaInfo.PremultipliedLast.rawValue 
     return CGBitmapContextCreate(nil, Int(ceil(size.width)), Int(ceil(size.height)), 8, 0, sp, bi) 
    } 

    public var image: CGImage? { return CGBitmapContextCreateImage(self) } 

    public func draw(linearGradient 
     gradient: CGGradient?, 
     start: CGPoint, 
     end: CGPoint, 
     options: CGGradientDrawingOptions = [.DrawsBeforeStartLocation, .DrawsAfterEndLocation] 
     ) -> CGContext 
    { 
     CGContextDrawLinearGradient(self, gradient, start, end, options) 
     return self 
    } 
} 

Wenn Sie dies auf einem Spielplatz ausprobieren möchten, können Sie dies alles in kleben, mit vorangestellter folgenden Ausschnitt (für OS X) dafür, dass Sie haben die Zeitleiste des Spielplatz in Schnittassistenz:

import XCPlayground 
import Cocoa 
import SpriteKit 

let scene = SKScene(size: CGSize(width: 400, height: 400)) 
let view = SKView(frame: CGRect(origin: .zero, size: scene.size)) 
XCPlaygroundPage.currentPage.liveView = view 
view.presentScene(scene) 
+0

WOW !!!! SIE SIND PHÄNOMENAL !!Ich bekomme jedoch einen Fehler für "CGColorCreateGenericRGB (r, g, b, alpha) zurückgeben" sagt, dass es nicht verfügbar ist. Irgendwelche Arbeiten herum dafür? Ich importierte CoreGraphics wie die Apple-Dokumentation sagt aber immernoch nichts. – OriginalAlchemist

+0

ERHALTEN SIE ES! benutze dies: return UIColor (rot: r, grün: g, blau: b, alpha: alpha) .CGColor. DANKE SO SO VIEL! Ich schätze das wirklich sehr! – OriginalAlchemist

+0

Eigentlich letzte Frage! Jetzt geht es von AliceBlue & BurlyWood zu AliceBlue und CornflowerBlue. Was ist der beste Weg, einen anderen Satz zu erstellen, um von und zu verschiedenen Farben zu gehen. Zum Beispiel, nachdem es von AliceBlue & BurlyWood zu AliceBlue und CornflowerBlue geht, möchte ich, dass es von Red & Yellow zu Green & Blue geht. Würde ich einen anderen HorizontalGradientNode instanziieren? – OriginalAlchemist

0

In den Kommentaren folgt meine erste Antwort @ OriginalAlchemist gefragt, ob die HorizontalGradientNode kann geändert werden, um durch mehr als zwei Sätze von Farben Zyklus. Hier ist eine Möglichkeit, es zu tun (CGImage.withHorizontalGradient(size:colors:) von meiner ersten Antwort unter der Annahme vorhanden ist):

class HorizontalGradientNode : SKNode { 

    init(size: CGSize, gradientColorSets: [[CGColor]], wait: NSTimeInterval, duration: NSTimeInterval) { 
     super.init() 

     var i = 0 
     let setNextGradientTexture = SKAction.customActionWithDuration(0) { (node, _) in 
      guard let sprite = node as? SKSpriteNode else { return } 
      let colors = gradientColorSets[i] 
      i = (i + 1) % gradientColorSets.count 
      guard let image = CGImage.withHorizontalGradient(size: size, colors: colors) else { return } 
      sprite.texture = SKTexture(CGImage: image) 
      sprite.size = sprite.texture!.size() 
     } 

     let sprite1 = SKSpriteNode() 
     let sprite2 = SKSpriteNode() 

     sprite1.runAction(setNextGradientTexture) 

     sprite2.alpha = 0 
     sprite2.runAction(
      .repeatActionForever(
       .sequence(
        [ 
         setNextGradientTexture, 
         .waitForDuration(wait), 
         .fadeInWithDuration(duration), 
         .runBlock({ sprite1.runAction(setNextGradientTexture) }), 
         .waitForDuration(wait), 
         .fadeOutWithDuration(duration) 
        ] 
       ) 
      ) 
     ) 

     addChild(sprite1) 
     addChild(sprite2) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 
} 

Verbrauch:

// assuming 
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5) 

let gradientColorSets: [[CGColor]] = [ 
    [.AliceBlue, .BurlyWood], // note that you can have more than two colours per set 
    [.BurlyWood, .CornflowerBlue], 
    [.CornflowerBlue, .ForestGreen], 
    [.ForestGreen, .AliceBlue] 
] 

let bg = HorizontalGradientNode(size: scene.size, gradientColorSets: gradientColorSets, wait: 1, duration: 2) 
scene.addChild(bg) 

@OriginalAlchemist auch bat um eine iOS-kompatible Version der benannten CGColors:

public extension CGColor { 

    public static func withHex(hex: Int, alpha: CGFloat = 1) -> CGColor { 
     let x = max(0, min(hex, 0xffffff)) // allows force unwrapping of the return value 
     let r = CGFloat((x & 0xff0000) >> 16) /0xff 
     let g = CGFloat((x & 0x00ff00) >> 8) /0xff 
     let b = CGFloat(x & 0x0000ff)  /0xff 
     let cp = CGColorSpaceCreateDeviceRGB() 
     return CGColorCreate(cp, [r, g, b, alpha])! 
    } 

    public static var AliceBlue: CGColor { return .withHex(0xF0F8FF) } 
    public static var BurlyWood: CGColor { return .withHex(0xDEB887) } 
    public static var CornflowerBlue: CGColor { return .withHex(0x6495ED) } 
    public static var ForestGreen: CGColor { return .withHex(0x228B22) } 
    // see named colours at: http://www.w3schools.com/colors/colors_names.asp 
} 
+0

Wow, du bist ein erstaunlicher Mann. Ich danke dir sehr. Das hilft sehr. Hier ist meine E-Mail: [email protected] Du kannst mir eine E-Mail schreiben und in Verbindung bleiben, ich werde mich daran erinnern und wenn sich eine Gelegenheit bietet, weiß ich, zu wem ich gehen soll !! Auch wenn und nur wenn Sie Zeit haben und sich wirklich großzügig fühlen, habe ich hier eine andere Frage gestellt und würde etwas Hilfe lieben: http://stackoverflow.com/questions/36234960/skemiternode-with-avaudioplayer-for-music-visuals. Nochmals vielen Dank! Beeindruckend! – OriginalAlchemist