Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

9. diel - Pridanie Parallax efektu a životov hráča vo SpriteKit

V predchádzajúcej lekcii, Ďalšie časticové efekty vo SpriteKit , sme dokončili snáď jednu z najobsiahlejších častí našej iOS hry vo Swift - fyziku a kolízie. Takže na dokončenie Galaxy Invaders už ostávajú len drobnosti.

Strely zničených nepriateľov

V prvom rade vyriešime problém laserové strely, ktorú nepriateľ vystrelí krátko pred svojím zničením. Takáto strela sa môže objaviť tam, kde už nepriateľ nie je, čo pôsobí, ako by sa tam zrazu objavila sama. Strela totiž čaká neviditeľná, vďaka čomu nepriatelia nestrieľa v rovnakých intervaloch.

Ideálne potrebujeme mechanizmus, ktorý strelu zruší v prípade, že už má dôjsť k jej zviditeľneniu (skutočnému vystrelenie) a daný nepriateľ je v tej chvíli už zničený.

Uloženie aktuálnej strely

Začneme pridaním vlastnosti currentShot triede Enemy:

weak var currentShot: SKNode?

Tá v sebe bude dočasne držať aktuálne strelu. Pre istotu je weak, aby prípadne nebránila správnej delokácia.

Pri vytvorení strely v metóde createLaserFire() ju nastavíme:

currentShot = laser

Úprava laserMovement

V triede Enemy už zostáva len úprava premenné laserMovement, vracajúci sekvenciu s pohybom nepriateľské strely. Túto sekvenciu potrebujeme odovzdať inštanciu nepriateľa, pre ktorú strelu vytvárame, takže ju premeníme na statickú funkciu:

static func laserMovement(for enemy: Enemy) -> SKAction

A pridáme jednu SKAction. Upravené telo funkcie vyzerá nasledovne:

let randomWait = SKAction.wait(forDuration: Double.random(in: 0...2))
let setCurrentShotNil = SKAction.run { [weak enemy] in
    enemy?.currentShot = nil
}
let fadeIn = SKAction.fadeIn(withDuration: 0.2)
let move = SKAction.moveBy(x: 0, y: -1500, duration: 2.5)
let remove = SKAction.removeFromParent()
return SKAction.sequence([randomWait, setCurrentShotNil, fadeIn, move, remove])

Pridali sme akciu setCurrentShotNil, kde vďaka SKAction.run môžeme vykonať akýkoľvek kus kódu. Tu nastavíme currentShot na nil. Túto akciu spustíme v sekvencii hneď po náhodnom čakania.

Pokiaľ má zničený nepriateľ nastavenú premennú currentShot, tak to teda znamená, že strela stále neviditeľne čaká a ešte nebola na nil nastavená.

Zavolanie metódy

Teraz musíme upraviť, ako sa metóda volá. Prejdeme teda do GameScene a najprv upravíme metódu enemyFireTimerTick(), konkrétne tento riadok:

laser.run(Enemy.laserMovement(for: child))

Potom stačí posledná úprava vo funkcii missileHit(). Trebárs hneď za explóziu pridáme novú if let konštrukciu:

if let enemy = enemy as? Enemy {
    enemy.currentShot?.removeAllActions()
    enemy.currentShot?.removeFromParent()
}

Ak strela nepriateľa stále neviditeľne čaká, odstránime z nej všetky akcie a celkovo ju odoberieme. Ak už čakania prebehlo, tak skoršie akcie setCurrentShotNil nastavila premennú na nil a nemôže sa nám stať, že by sme omylom odobrali strelu, ktorá už letí smerom k lodi hráča.

Bolo to síce komplikovanejšie, ale odstránili sme problém a ukázali si ďalšie možnosti SKAction.

Parallax efekt

Tento efekt nájdete vo veľa 2D hier, pretože je jednoduchý a krásne vytvára efekt hĺbky. Nejde pritom o nič komplexného. Základný variant používa dve alebo viac nekonečných pozadia, ktoré sú priehľadné a prekrývajú sa. Pozadie sa stále dookola pohybujú, ale každé inou rýchlosťou. Je to podobné, ako keď idete napr. Vlakom a pozeráte sa von z okienka. Stĺpy okolo trate sa mihajú veľmi rýchlo, vzdialenejšie stromy pomalšie a kopce v diaľke sa posúvajú už len veľmi pomaly. Práve týmto vzniká efekt hĺbky pozadia za hrou:

Efekt paralaxního pozadia v 2D hrách - Tvorba iOS hier vo Swift

My teda vlastne potrebujeme zabezpečiť dve nekonečne scrollující pozadie, každé s inou rýchlosťou. To základný s vesmírom, ktoré zaberá celú hernú obrazovku, už máme. Bude ho teda stačiť iba rozpohybovať. Druhé si môžete vytvoriť alebo použiť mojej pozadia s meteory nižšie.

Prvý pozadia - Vesmír

Nekonečné scrollovanie môže znieť ako výzva, jedná sa ale iba o dve textúry, ktoré sa pohybujú za sebou a vracia späť na začiatok. To je celé. Uvidíte, že pomocou SKAction to bude hotové raz dva.

Konfiguračný metóda

Začneme s deklaráciou metódy, ktorá pozadia pripraví:

func configureParallax(for imageName: String, duration: TimeInterval, zPosition: CGFloat) {
}

Túto metódu potom len zavoláme pre jednotlivé pozadia, aby sme nemuseli programovať každé zvlášť. A ako prvý vytvoríme prvý objekt pozadia:

let firstNode = SKSpriteNode(imageNamed: imageName)
firstNode.zPosition = zPosition
firstNode.anchorPoint = .zero

Nastavujeme tiež anchorPoint pre ľahšie výpočty. Potom už stačí pomocou kopírovania vytvoriť identické pozadia a pridať obe do scény. Obe pozadia, ktorá na seba nadväzujú, budeme posúvať dole a akonáhle jedno vyjde z obrazovky, premiestnime ho nad to druhé. Týmto spôsobom sa budú stále vymieňať a vo viditeľnej časti obrazovky to bude vyzerať, že je pozadie nekonečné.

let secondNode = firstNode.copy() as! SKSpriteNode
secondNode.position.y += secondNode.size.height - 1

addChild(firstNode)
addChild(secondNode)

Druhou textúru posunieme nahor o jej výšku a odpočítame pixel, aby sme náhodou nemali medzeru v našom efektu.

Posledným krokom je definícia nekonečné sekvencia SKAction a ich spustenie pre obe textúry pozadia:

let move = SKAction.moveBy(x: 0, y: -firstNode.size.height, duration: duration)
let reset = SKAction.moveBy(x: 0, y: firstNode.size.height, duration: 0)
let loop = SKAction.sequence([move, reset])
let forever = SKAction.repeatForever(loop)

firstNode.run(forever)
secondNode.run(forever)

DidMove ()

Teraz zostáva v didMove() zavolať nastavenie Parallax efektu a zmazať staršie createBackground():

configureParallax(for: "background", duration: 25, zPosition: -5)

A vyskúšame:

Tvorba iOS hier vo Swift

Aby ste mohli názorne vidieť, čo sa deje, nahradil som dočasne naše pozadia dvojicou rôznofarebného a zrýchlil:

Paralaxní pozadia v SpriteKit - Tvorba iOS hier vo Swift

Druhé pozadia - Meteory

Pre Parallax samozrejme potrebujeme aspoň dve pozadia. Keďže celú prípravu máme hotovú, bude pridanie meteorov otázka iba ďalšieho zavolaní metódy configureParallax():

configureParallax(for: "meteors", duration: 15, zPosition: -4)

Použitý obrázok je k stiahnutiu nižšie:

Tvorba iOS hier vo Swift

A výsledok:

Tvorba iOS hier vo Swift

Životy hráča

Náš hráč je stále nesmrteľný. Túto superschopnosti mu teraz odoberieme a bude sa musieť spoľahnúť na tradičné tri životy.

Aby hráč vedel, koľko životov mu zostáva, vypíšeme si ich ako text. Životy by sme samozrejme mohli reprezentovať napríklad obrázky sŕdc alebo miniatúrou lodi hráča, takto si ale ukážeme prácu s SKLabelNode, ktorá slúži práve na zobrazovanie textu.

Definície labelu a životov

Najskôr si v GameScene definujeme premennú pre SKLabelNode a rovno aj pre počet životov:

let livesLabel = SKLabelNode(fontNamed: "Verdana-Bold")
var lives: Int = 3 {
    didSet {
        livesLabel.text = "LIVES: \(lives)"
    }
}

Pomocou didSet() automaticky nastavíme text na aktuálny počet životov.

Pridanie do scény

Ďalej si pripravíme metódu, ktorá livesLabel nastaví a pridá do scény:

func setupLivesLabel() {
    livesLabel.verticalAlignmentMode = .top
    livesLabel.position = CGPoint(x: frame.midX, y: frame.maxY - 70)
    addChild(livesLabel)
    lives = 3
}

Nastavenie verticalAlignmentMode určuje, od akého okraja sa počíta pozície na osi Y. Existuje ešte horizontalAlignmentMode, ktoré to isté robí pre os X. V predvolenom stave sú nastavené na hodnotu .center. Takže náš label nastavíme k hornej hrane a na horizontálne stred.

Explicitne je tu ešte nastavenie premennej lives, aby došlo k aktivácii didSet() a korektne sa nastavil text.

Zavolanie metódy

Zostáva metódu zavolať vnútri didMove():

setupLivesLabel()

Posledné, čo v tejto lekcii vykonáme, je zníženie životov o jeden, ak je hráč zasiahnutý laserom. To urobíme v metóde laserHitPlayer():

lives -= 1

Korektnejšie by samozrejme bolo mať životy v triede Player, ale potom by sme museli zložitejšie aktualizovať label. Pre naše potreby súčasné riešenie stačí.

Tvorba iOS hier vo Swift

V ďalšej lekcii, Poškodenie hráča, menu hry a reštart vo SpriteKit , pridáme poškodenie, koniec hry a ukážeme si, ako vytvoriť herný menu.

V ďalšej lekcii, Poškodenie hráča, menu hry a reštart vo SpriteKit , pridáme poškodenie, koniec hry a ukážeme si, ako vytvoriť herný menu.


 

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é 4x (1000.31 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Swift

 

Predchádzajúci článok
Ďalšie časticové efekty vo SpriteKit
Všetky články v sekcii
Tvorba iOS hier vo Swift
Preskočiť článok
(neodporúčame)
Poškodenie hráča, menu hry a reštart vo SpriteKit
Č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