7. diel - Dokončenie kolízií vo SpriteKit
V minulej lekcii, Pridanie fyziky a detekcia kolízií vo SpriteKit , sme skončili pri metódy
didBegin()
, ktorá nás informuje o kolízii medzi objektmi, pre
ktoré sme notifikácia zapli. Dnes všetko sprevádzkujeme, takže hráč bude
môcť konečne ničiť nepriateľov.
Zistenia konfliktu s už existujúcim objektu
Od SpriteKit dostaneme v metóde didBegin()
parameter
contact
typu SKPhysicsContact
, ktorý nás informuje o
tom, aké dva objekty kolidovali. Tradičné implementácia tejto metódy v
prvom rade vytiahne obaja SKNode
objekty pomocou
guard
:
guard let nodeA = contact.bodyA.node else { return } guard let nodeB = contact.bodyB.node else { return }
Vďaka tomu vieme, že môžeme kolízii spracovať, pretože máme oba objekty. Lenže, čo z toho je raketa? Laser? Loď hráča?
Názvy objektov
Všetky SKNode
majú vlastnosť name
, ktorá nám v
tomto pomôže. Vrátime sa teda najskôr do triedy Player
a v
init()
nastavíme vlastnosť name
:
name = "player"
Podobne si nastavíme rakety:
let missile1 = SKSpriteNode(imageNamed: "playerMissile") missile1.name = "missile" let missile2 = missile1.copy() as! SKSpriteNode
Využívame kopírovanie, takže meno stačí nastaviť iba raz.
Naša hra má dosť jednoduché kolízie a ak by sme zistili, že jeden objekt je loď hráča, tak druhý musí byť logicky laser. Napriek tomu odporúčam pomenovať si poctivo všetky objekty, nech je kód vo výsledku čitateľnejší.
Zostáva nastaviť mená v triede Enemy
:
enemy.name = "enemy"
A laser:
laser.name = "laser"
DidBegin ()
Po krátkej odbočke sa môžeme vrátiť do metódy didBegin()
.
Spracovanie kolízie rozdelíme a najskôr vyriešime situáciu, kedy raketa
trafí nepriateľa.
Pre prehľadnosť si pripravíme metódu, ktorá sa postará práve o túto
situáciu. V didBegin()
ju teda stačí iba správne poslať oba
objekty a bod, kde došlo ku kontaktu:
func missileHit(_ missile: SKNode, enemy: SKNode, at point: CGPoint) {
}
A zistenie, aký z objektov je raketa a aký nepriateľ, vyzerá potom nasledovne:
if nodeA.name == "missile" || nodeB.name == "missile" { if nodeA.name == "enemy" { missileHit(nodeB, enemy: nodeA, at: contact.contactPoint) } else { missileHit(nodeA, enemy: nodeB, at: contact.contactPoint) } }
Zásah
Poďme na kolíziu nejako reagovať. V metóde missileHit()
pre
začiatok pri kolízii odstránime oba objekty zo scény:
missile.removeFromParent() enemy.removeFromParent()
Pole enemies
Lenže nepriateľov máme uložené tiež v poli enemies
, ktoré
slúžia pre ľahký prístup k nim, keď chceme, aby strieľali. Máme na
výber, buď sa starať o to, aby sme zasiahnuté nepriateľov odstránili aj z
poľa, alebo to vymyslieť lepšie, aby pole nebolo potrebné.
GameScene
ponúka vlastnosť children
obsahujúce
všetky objekty v scéne. My ale používame enemyAnchor
pre
jednoduchú animáciu pohybu nepriateľov, takže už je vlastne v jednej
kolekcii máme.
Jednoducho teda premennú enemies
zmažeme. Ďalej je potrebné
upraviť createEnemyWave()
a odstrániť pridávanie nových
nepriateľov do už zmazaného poľa. Posledný nutnou úpravou je metóda
enemyFireTimerTick()
.
Namiesto pole enemies
budeme cez for
cyklus
iterovat enemyAnchor.children
, ktorý ale vracia pole typu
[SKNode]
. Je hromada spôsobov, ako sa s týmto vysporiadať. Mohli
by sme napríklad pretypovanie vykonávať cez guard
alebo
if let
v tele cykle.
My ale využijeme silné možnosti, tzv. Pattern matching, pomocou
case let
zápisu. Rovno si ho ukážeme celý:
for case let child as Enemy in enemyAnchor.children
Ak vás for case let
za sebou vydesilo, ani sa nevidím.
Prvýkrát som na tento zápis pozeral dosť neveriacky. Postará sa o to, aby
lokálna premenná child
bola typu Enemy
a my s ňou
mohli pracovať ako predtým. Samozrejme je nutné premenovať skorší lokálnu
premennú enemy
v tele cyklu na child
.
Pomocou case let
môžete vo for
cykle
jednoducho rozbaľovať Optional
hodnoty, stačilo by namiesto
child
napísať child?
. Ak by sme pracovali s poľom
Optional
hodnôt, v tele cyklu by už Optional
nebolo.
Rovnako tak sa case let
dá využiť v konštrukcii
switch
.
Hru môžeme zapnúť a presvedčiť sa, že rakety konečne likvidujú protivníkov:
Oprava kolízií
Hádam, že ste si všimli, že kolízie fungujú divne pri zásahu rakety. Niekedy dokonca akoby raketa ignorovala nepriateľa a letela ďalej.
SpriteKit nám ponúka pomerne jednoduchú možnosť, ako overiť nastavenie
fyzikálne reprezentácie pre objekty. Prejdeme teda do
GameViewController.swift
a v metóde viewDidLoad()
nájdeme riadok view.showsNodeCount = true
.
Ako prezrádza názov, určuje, či má scéna zobrazovať počet objektov. To je pre prípad, aby sme si overili, že korektne odoberáme tie už nepotrebné. Pridáme ďalší riadok a to:
view.showsPhysics = true
Ide o ďalší debug konfigurácii pre zobrazenie fyziky. Aktuálne nastavené fyzikálne reprezentácie objektov budú zobrazené bledomodrým obrysom. Zapneme hru a okamžite vidíme, kde je problém:
Ako sami vidíte, fyzikálne reprezentácie a vykreslenie nepriateľov
nesedí, zvyšok funguje dobre. Problém je v nastavení
anchorPoint
pre naše nepriateľov. Neuvedomil som si v
predchádzajúcej lekcii, že ide iba o vizuálne nastavenie vykresľovania a
neskôr nastane problém s fyzikou. Tak sme si aspoň mohli ukázať, ako
problémy hľadať.
Zmena anchorPoint
Ak by sme vytvárali fyzikálne reprezentáciu ako obdĺžnik alebo kruh,
išlo by posunúť stred a tým problém vyriešiť. My ale používame
textúru, takže nám nezostáva nič iné, než nastavenie
anchorPoint
vrátiť späť a upraviť kód generovanie vlny
nepriateľov, aby boli na stredu.
Úpravy teda vykonáme v metóde createEnemyWave()
. Najskôr
odstránime nastavenie anchorPoint
a potom upravíme počítanie
xPosition
v tele cykle takto:
let xPosition = xOffset + CGFloat(i) * (enemySize + enemySpacing) + enemySize / 2
Vlastne sme pridali pripočítanie polovice šírky nepriateľa, ako
kompenzáciu za upravený anchorPoint
.
Môžeme skúsiť:
Teraz už budú kolízie fungovať podľa očakávania V budúcej lekcii, Ďalšie časticové efekty vo SpriteKit , pridáme časticové efekty explózie a lasera
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é 8x (987.57 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Swift