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:
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:
Aby ste mohli názorne vidieť, čo sa deje, nahradil som dočasne naše pozadia dvojicou rôznofarebného a zrýchlil:
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:
A výsledok:
Ž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čí.
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