2016-09-02 11 views
5

Buduję swoją pierwszą grę za pomocą Swift i SpriteKit i chcę dodać tło. Gra toczy się w kosmosie, więc chciałem mieć gwiazdy w tle poruszające się z różną prędkością. Obecnie zamierzam uzyskać wygląd 3D, dzięki czemu większe gwiazdy poruszają się po ekranie szybciej niż mniejsze. Czy istnieje skuteczny sposób, aby to zrobić zamiast tworzyć podklasę SKNode w ten sposób i dodawać ją jako dziecko na początku DidMoveToView? Wygląda na to, że ta metoda jest dość intensywna, ale pomyślałem, że wypróbuję ją, zanim powtórzę ten sam obraz w kółko.Animacja tła z głębią w SpriteKit

class BackGroundAnimation:SKNode{ 

let theView:SKView 
init(aView:SKView){ 

    theView = aView 

    super.init() 

    animate() 
} 


func animate(){ 


    for _ in 1...200{ 

     let randomSize = random(1, max: 3) 
     var randomPosx = random(1,max: 1000) 
     randomPosx = randomPosx/1000.0 
     var randomPosy = random(1,max: 1000) 
     randomPosy = randomPosy/1000.0 

     let star:SKSpriteNode = SKSpriteNode(texture:starTexture) 
     star.setScale(randomSize/60.0) 



     star.position = CGPoint(x:(theView.scene?.size.width)! * randomPosx,y:(theView.scene?.size.width)! * randomPosy)// (self.scene.size.width)*randomPosx, y:(self.scene.size.height) * randomPosy) 

     //star.position = CGPoint(x: 200,y: 200) 

     star.physicsBody = SKPhysicsBody(circleOfRadius: star.size.width/2) 
     star.physicsBody?.collisionBitMask = 0 
     star.physicsBody?.categoryBitMask = 0 
     star.physicsBody?.contactTestBitMask = 0 

     star.physicsBody?.linearDamping = 0 
     star.physicsBody?.velocity = CGVector(dx:1 * randomSize, dy:0) 
     star.name = "star" 

     //addChild(star) 
     self.addChild(star) 
     self.moveToParent(self.scene!) 


    } 


} 




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

}

Każda pomoc będzie wielki.

+0

Uważam, że metoda, z której obecnie korzystasz, jest właściwym sposobem implementacji tego typu tła.Jednakże, jeśli zauważysz ekstremalne opóźnienie i/lub powolne działanie (z powodu tła) na prawdziwych urządzeniach (nie symulatorach), spróbuję zepsuć ich części i przenieść je do części tła, które naprawdę potrzebujesz – Nik

+0

Możesz użyć cząstki i po prostu mają 3 warstwy cząsteczek renderujące z różnymi prędkościami i to wszystko. Zrzut ekranu z tego, co mam na myśli: https://twitter.com/JozemiteApps/status/678734299521155072. –

+0

Sprawdź w SKEmitterNode –

Odpowiedz

6

Jak wspomniałem w komentarzu, można stworzyć piękne tło paralaksy za pomocą cząstek.

Dodaj tę funkcję w dowolnym miejscu w klasie.

//Creates a new star field 
func starfieldEmitterNode(speed speed: CGFloat, lifetime: CGFloat, scale: CGFloat, birthRate: CGFloat, color: SKColor) -> SKEmitterNode { 
    let star = SKLabelNode(fontNamed: "Helvetica") 
    star.fontSize = 80.0 
    star.text = "✦" 
    let textureView = SKView() 
    let texture = textureView.textureFromNode(star) 
    texture!.filteringMode = .Nearest 

    let emitterNode = SKEmitterNode() 
    emitterNode.particleTexture = texture 
    emitterNode.particleBirthRate = birthRate 
    emitterNode.particleColor = color 
    emitterNode.particleLifetime = lifetime 
    emitterNode.particleSpeed = speed 
    emitterNode.particleScale = scale 
    emitterNode.particleColorBlendFactor = 1 
    emitterNode.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMaxY(frame)) 
    emitterNode.particlePositionRange = CGVector(dx: CGRectGetMaxX(frame), dy: 0) 
    emitterNode.particleSpeedRange = 16.0 

    //Rotates the stars 
    emitterNode.particleAction = SKAction.repeatActionForever(SKAction.sequence([ 
     SKAction.rotateByAngle(CGFloat(-M_PI_4), duration: 1), 
     SKAction.rotateByAngle(CGFloat(M_PI_4), duration: 1)])) 

    //Causes the stars to twinkle 
    let twinkles = 20 
    let colorSequence = SKKeyframeSequence(capacity: twinkles*2) 
    let twinkleTime = 1.0/CGFloat(twinkles) 
    for i in 0..<twinkles { 
     colorSequence.addKeyframeValue(SKColor.whiteColor(),time: CGFloat(i) * 2 * twinkleTime/2) 
     colorSequence.addKeyframeValue(SKColor.yellowColor(), time: (CGFloat(i) * 2 + 1) * twinkleTime/2) 
    } 
    emitterNode.particleColorSequence = colorSequence 

    emitterNode.advanceSimulationTime(NSTimeInterval(lifetime)) 
    return emitterNode 
} 

A następnie dodaj tę funkcję. Jest to funkcja, która stworzy warstwy gwiazd. Po prostu wywołaj tę funkcję, na przykład w didMoveToView.

func createStarLayers() { 
    //A layer of a star field 
    let starfieldNode = SKNode() 
    starfieldNode.name = "starfieldNode" 
    starfieldNode.addChild(starfieldEmitterNode(speed: -48, lifetime: size.height/23, scale: 0.2, birthRate: 1, color: SKColor.lightGrayColor())) 
    addChild(starfieldNode) 

    //A second layer of stars 
    var emitterNode = starfieldEmitterNode(speed: -32, lifetime: size.height/10, scale: 0.14, birthRate: 2, color: SKColor.grayColor()) 
    emitterNode.zPosition = -10 
    starfieldNode.addChild(emitterNode) 

    //A third layer 
    emitterNode = starfieldEmitterNode(speed: -20, lifetime: size.height/5, scale: 0.1, birthRate: 5, color: SKColor.darkGrayColor()) 
    starfieldNode.addChild(emitterNode) 
} 

I tak to wygląda.

enter image description here

+0

@Nik czy nie wiesz, czym jest emiter cząstek? Kończysz tysiące niezależnych ruchomych duszków. Użyj tego podejścia tylko wtedy, gdy nie planujesz intensywnej pracy z GPU i procesorem. – Knight0fDragon

+0

@ Knight0fDragon Więc to nie jest dobre podejście? Przepraszam, nie jestem z nim dobrze zaznajomiony – Nik

+0

@ Knight0fDragon Obecnie mam coś podobnego do twojej obecnej odpowiedzi – Nik

1

Sposobem na to zrobić bez cząstek jest tworzenie warstwy i po prostu przenieść poszczególne warstwy

więc stworzyć SKNode tła, wypełnić go ze swoimi duszków tła

Tworzenie nowej wiedzy SKNode, wypełnij go swoimi pierwszymi obiektami graficznymi:

Dodaj tło jako dziecko nowej wiedzy, nadaj mu wartość zPosition wynoszącą co najmniej -1

Następnie przesuwasz pierwszy plan, niezależnie od tego, co przesuniesz na pierwszym planie, przesuwasz tło w przeciwnym kierunku, zwykle na mniejszy procent (lubię używać połowy). Jeśli pierwszy plan przesuwa 10 pikseli w lewo, przenieść tle 5 pikseli w prawo

Ponieważ wszystkie węzły są wewnątrz tych warstw, wszystkie węzły ruszy podczas przesuwania warstwy

1

Aktualizacja rozwiązanie @JozemiteApps dla Swift 4/iOS 11

Dodaj tę funkcję w dowolnym miejscu w swojej klasie.

//Creates a new star field 
func starfieldEmitterNode(speed speed: CGFloat, lifetime: CGFloat, scale: CGFloat, birthRate: CGFloat, color: SKColor) -> SKEmitterNode { 
    let star = SKLabelNode(fontNamed: "Helvetica") 
    star.fontSize = 80.0 
    star.text = "✦" 
    let textureView = SKView() 
    let texture = textureView.texture(from: star) 
    texture!.filteringMode = .nearest 

    let emitterNode = SKEmitterNode() 
    emitterNode.particleTexture = texture 
    emitterNode.particleBirthRate = birthRate 
    emitterNode.particleColor = color 
    emitterNode.particleLifetime = lifetime 
    emitterNode.particleSpeed = speed 
    emitterNode.particleScale = scale 
    emitterNode.particleColorBlendFactor = 1 
    emitterNode.position = CGPoint(x: frame.midX, y: frame.maxY) 
    emitterNode.particlePositionRange = CGVector(dx: frame.maxX, dy: 0) 
    emitterNode.particleSpeedRange = 16.0 

    //Rotates the stars 
    emitterNode.particleAction = SKAction.repeatForever(SKAction.sequence([ 
     SKAction.rotate(byAngle: CGFloat(-Double.pi/4), duration: 1), 
     SKAction.rotate(byAngle: CGFloat(Double.pi/4), duration: 1)])) 

    //Causes the stars to twinkle 
    let twinkles = 20 
    let colorSequence = SKKeyframeSequence(capacity: twinkles*2) 
    let twinkleTime = 1.0/CGFloat(twinkles) 
    for i in 0..<twinkles { 
     colorSequence.addKeyframeValue(SKColor.white,time: CGFloat(i) * 2 * twinkleTime/2) 
     colorSequence.addKeyframeValue(SKColor.yellow, time: (CGFloat(i) * 2 + 1) * twinkleTime/2) 
    } 
    emitterNode.particleColorSequence = colorSequence 

    emitterNode.advanceSimulationTime(TimeInterval(lifetime)) 
    return emitterNode 
} 

A następnie dodaj tę funkcję. Jest to funkcja, która stworzy warstwy gwiazd. Po prostu wywołaj tę funkcję, na przykład w didMoveToView.

func createStarLayers() { 
     //A layer of a star field 
     let starfieldNode = SKNode() 
     starfieldNode.name = "starfieldNode" 
     starfieldNode.addChild(starfieldEmitterNode(speed: -48, lifetime: size.height/23, scale: 0.2, birthRate: 1, color: SKColor.lightGray)) 
     addChild(starfieldNode) 

     //A second layer of stars 
     var emitterNode = starfieldEmitterNode(speed: -32, lifetime: size.height/10, scale: 0.14, birthRate: 2, color: SKColor.gray) 
     emitterNode.zPosition = -10 
     starfieldNode.addChild(emitterNode) 

     //A third layer 
     emitterNode = starfieldEmitterNode(speed: -20, lifetime: size.height/5, scale: 0.1, birthRate: 5, color: SKColor.darkGray) 
     starfieldNode.addChild(emitterNode) 
    } 
+1

Uwaga wygląda na to, że cząsteczki Akcji nie działają w iOS 10 + – bamboostickk