IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

11. diel - Nekonečné vlny nepriateľov a ich animácie vo SpriteKit

V predchádzajúcej lekcii, Poškodenie hráča, menu hry a reštart vo SpriteKit , sme si ukázali okrem iného ako implementovať menu hry a pridali reštart, ak hráča nepriatelia zničí. Hráč ale stále môže skôr zničiť vlnu nepriateľov a potom už nerušene pokračovať v hre, pretože sa ďalej nič nestane.

Na dokončenie hry nám zostáva upraviť, ako fungujú vlny nepriateľov, aby sa po zničení objavila nová. Pripravíme si novú metódu createEnemies(), ktorá sa bude starať o vytvorenie všetkých nepriateľov a tiež animáciu ich príletu na scénu.

Náhodné formácie nepriateľov

Aktuálne používame metódu createEnemyWave(), ktorá vytvorí vlnu nepriateľov podľa zadaného počtu. My by sme však potrebovali, aby sa vlny od seba nelíšili len počtom nepriateľov, ale aj formácií, v ktorej letí.

createEnemyWave()

Najprv upravíme createEnemyWave(), aby brala do úvahy rady nepriateľov. Pridáme teda parameter row typu Int:

func createEnemyWave(enemyCount: Int, row: Int)

Po úprave tiež zmažeme volanie metódy v didMove(), nech na nás Xcode nekričí, že nesedí parametre.

A vnútri metódy nad cyklom vypočítame pozíciu y:

let yPosition: CGFloat = CGFloat(row) * 120

Tú potom nastavíme nepriateľom v tele cyklu:

newEnemy.position = CGPoint(x: xPosition, y: yPosition)

Na záver pridáme náhodný výber typu nepriateľov upravením volanie Enemy.create() na začiatku metódy:

let enemyTemplate = Enemy.create(variant: Int.random(in: 1...3))

createEnemies()

A teraz sa môžeme pustiť do metódy createEnemies():

func createEnemies() {
    let rows = Int.random(in: 2...3)
    for row in 1...rows {
        createEnemyWave(enemyCount: Int.random(in: 3...5), row: row)
    }
}

Odmenou za celkom zložitú metódu createEnemyWave() je jej jednoduché použitie, keď chceme podľa náhody pripraviť dve alebo tri rady nepriateľov a v každej mať v rozmedzí od 3 do 5 nepriateľských lodí.

setupEnemyAnchor()

Ešte musíme upraviť metódu setupEnemyAnchor(), konkrétne pozícii, aby bolo miesto na tri rady nepriateľov:

enemyAnchor.position = CGPoint(x: 0, y: size.height - 550)

Môžeme vyskúšať:

Tvorba iOS hier vo Swift

Každé zavolanie createEnemies() vytvorí náhodnú nepriateľskú formáciu:-)

Generovanie nových nepriateľov

Teraz stačí pridať animáciu prílete a generovať nové nepriateľov, keď hráč všetky zlikviduje.

IsGameInProgress

Musíme hlavne vyriešiť, aby nepriatelia nestrieľali, pokiaľ práve animuje ich prílet. Mohli by sme si vytvoriť ďalšie bool premennú. Prehľadnejšie a jednoduchšie bude ale upraviť súčasnú premennú isGameOver, ktorú premenujeme na všeobecnejšie isGameInProgress.

Zo začiatku bude nastavená aj na false a vždy ju nastavíme na true, keď nepriatelia priletia. Na false ju opäť nastavíme v prípade, keď hráč stratí všetky životy alebo zlikviduje všetkých nepriateľov. Začneme teda s premenovaním:

var isGameInProgress = false

lives

Upravíme didSet blok premennej lives:

if lives < 0 {
    isGameInProgress = false
    controller?.showGameOver()
    return
}

didBegin()

Ďalšia úpravu je potrebné vykonať na začiatku metódy didBegin():

guard isGameInProgress else { return }

enemyFireTimerTick()

A konečne v metóde enemyFireTimerTick(), kde na začiatok pridáme to isté:

guard isGameInProgress else { return }

To isté by sme mohli urobiť v metóde playerFireTimerTick(), ale vďaka kontrole v didBegin() sú rovnako rakety hráča neškodné. Opäť je to na vás.

enemyCount

Aby sme mohli zistiť, či už boli zničení všetci nepriatelia, pridáme si vlastnosť enemyCount, ktorá sa jednoducho opýta na potomkov enemyAnchor:

var enemyCount: Int {
    return enemyAnchor.children.count
}

missileHit()

Zostáva pridať kontrolu na koniec metódy missileHit(). Tu ale pozor. Nemôžeme sa na konci jednoducho opýtať na enemyCount, pretože nepriateľov ničíme najprv fadeOut akciou, ktorá nejaký čas trvá. Na enemyCount by sme sa teda spýtali skôr, než dôjde k zničeniu nepriateľa.

Zistil som, že na tomto riadku:

let fadeOut = SKAction.fadeOut(withDuration: 0.2)

Som mal preklep a použil som akciu SKAction.fadeIn() s opačným efektom, tak si to prosím opravte a ospravedlňujem sa za komplikácie:-)

Späť k nášmu problému. Vytvoríme si všeobecnú SKAction, ktorá skontroluje počet nepriateľov:

let createNewEnemiesIfNeeded = SKAction.run {
    if self.enemyCount == 0 {
        self.isGameInProgress = false
        self.createEnemies()
    }
}

A potom ju len pridáme na koniec existujúcej sekvencie:

let sequence = SKAction.sequence([fadeOut, SKAction.removeFromParent(), createNewEnemiesIfNeeded])

A máme nekonečné nepriateľov. Zostáva ich animácie.

Animácie vlny nepriateľov

Upravíme metódu createEnemies(), aby sa nepriatelia jednoducho neobjavili, ale namiesto toho prileteli. Na jej začiatok teda pridáme posunutie enemyAnchor mimo viditeľnú scénu a odstránenie všetkých akcií, pretože pre nepriateľov konfigurujeme nekonečný pohyb do strán. Takto by nám akurát rozhadzoval naše chystanej animácie.

enemyAnchor.position = CGPoint(x: 0, y: size.height + 700)
enemyAnchor.removeAllActions()

Ešte nezabudnite z metódy didMove() odstrániť volanie startEnemyMovement(). Rovnako tak môžeme prečistiť setupEnemyAnchor() a odstrániť nastavenie pozície:

enemyAnchor.position = CGPoint(x: 0, y: size.height - 550) // není již třeba

Posunutie pozície enemyAnchor vyššie by nám malo poskytnúť dosť priestoru na vytvorenie nepriateľov, bez toho aby boli vidieť.

Pod existujúcim for cyklom si pripravíme animácie a ďalšie SKAction:

let shrink = SKAction.scale(to: 0.7, duration: 0)
let moveIntoView = SKAction.moveTo(y: size.height - 550, duration: 3)
let resetSize = SKAction.scale(to: 1, duration: 3)
let group = SKAction.group([moveIntoView, resetSize])
let startGame = SKAction.run {
    self.isGameInProgress = true
    self.startEnemyMovement()
}

SKAction je veľa, ale nejedná sa o nič komplikovaného:-) Najskôr zmenšíme vytvorené nepriateľov a potom ich zároveň pomocou SKAction.group posunieme do viditeľnej scény a zväčšíme na pôvodnú veľkosť.

Potom už len cez SKAction.run spustíme hru, vrátane pohybu nepriateľov.

Môžeme vyskúšať:

Tvorba iOS hier vo Swift

A tým je naša vesmírna strieľačka Galaxy Invaders vo SpriteKit hotová. Ďakujem za záujem!:)

V tutoriále som sa snažil ukázať čo možno najviac techník a možností, ktoré nám SpriteKit ku tvorbe 2D hier pre iOS poskytuje. Ukázali sme si základnú prácu s textúrami a hernými objekty, celkom dosť sa venovali časticovým efektom, zapracovali sme kolízie pomocou fyziky a mnoho ďalšieho.

Možná vylepšenia

Do hry je toho možné samozrejme ešte kopu pridať. A či sa hrám plánujete venovať, rozhodne by som odporučil skúsiť si Galaxy Invaders čo najviac rozšíriť. Predsa len experimentovaním a úpravami sa môžete veľa naučiť.

Napríklad môžete pridať ďalšie zvukové efekty alebo napríklad hudbu na pozadí pomocou SKAudioNode, ktorú stačí len vytvoriť a pridať do scény. O prehrávanie audia sa postará sama a funguje v nekonečnej slučke.

Vlny nepriateľov aktuálne generujeme, lepšie by bolo nadefinovať ich a ponúknuť hráči, aby postupoval v úrovniach. Podľa danej úrovne môžete napríklad aj meniť, ako často nepriatelia strieľa. Rovnako tak by nebolo ťažké pridať viac typov pohybov nepriateľov a treba medzi nimi náhodne vyberať alebo skúsiť ponúknuť hráči súboj s jedným veľkým nepriateľom, ktorého nezničí jeden zásah, takže u neho bude treba ukladať poškodenia a napríklad aj zmeniť jeho bojový arzenál.

Ďalej môžete pridať napríklad power-upy, ktoré hráč pomocou kolízie zoberie. Napríklad rýchlejší frekvenciu streľby, doplnenie životov alebo zobratie štítu, ktorý balíček od Kenney.nl obsahuje.

A určite sami vymyslíte veľa ďalších možností, ako hru vylepšiť.

Nezabudnite, že svoje výsledné výtvory môžete nahrať na ITnetwork a trebárs ostatné inšpirovať alebo im ukázať, ako ďalšie rozšírenie implementovať.

Ak si nebudete vedieť s niečím rady, určite sa nebojte napísať do komentárov, na tunajšie fórum (kľudne ma môžete v príspevku označiť, nech o ňom viem) alebo do súkromných správ. Rád pomôžem, ak to bude v mojich silách.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 17x (1.73 MB)
Aplikácia je vrátane zdrojových kódov v jazyku Swift

 

Predchádzajúci článok
Poškodenie hráča, menu hry a reštart vo SpriteKit
Všetky články v sekcii
Tvorba iOS hier vo Swift
Článok pre vás napísal Filip Němeček
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity