2. diel - Pozadia, ovládanie hráča a časticové efekty vo SpriteKit
V predchádzajúcej lekcii, Úvod do tvorby iOS hier s frameworkom SpriteKit , sme si predstavili SpriteKit vrátane štruktúry projektu a nachystali textúry pre vesmírnu strieľačku. Teraz sa pustíme do budovania našej hry.
Nakopírovaniu textúr
Ako prvý krok je potrebné nakopírovať naše obrázky do
Assets.xcassets
v projekte a ideálne zvoliť nejaké výstižné a
jednoduché názvy. My si zvolíme background
pre pozadie a
player
pre loď hráča.
Pozíciovanie vo SpriteKit
Začneme s vytvorením pozadia. Než si pozadie pridáme do našej scény, potrebujeme si vysvetliť, ako funguje systém súradníc SpriteKit. V predvolenom stave totiž nezačína v ľavom hornom rohu ako UIKit.
Keď si otvoríte GameScene.sks
, tak napravo v Attributes
inšpektorovi môžete vidieť informácie o našej scéne. Nás zaujíma
položka "Anchor". Je to vlastne taká virtuálna kotva v scéne, podľa ktorej
sa budú umiestňovať ďalšie prvky.
V predvolenom stave je nastavená na X: 0.5
a Y:
0.5
. To znamená stred scény. V praxi sa používa buď toto
nastavenie alebo X: 0.0
a Y: 0.0
, čo znamená ľavý
dolný roh.
Rozhodnutie aký Anchor zvoliť je dosť podstatné a nejde urobiť
jednoznačné odporúčania. Záleží totiž na tom, ako je vaša hra
koncipovaná. Ak by sme tvorili hru, v ktorej bude obrazovka celá herná aréna
a hráč sa nebude pohybovať mimo, tak je najlogickejšie ponechať práve
0.5
; 0.5
a všetko nastavovať vzhľadom ku stredu.
Naša hra bude mať v spodnej časti loď hráča, ilúziu letu vesmírom a
nepriateľov v hornej časti obrazovky. Z pohľadu tejto hry dáva zmysel
použiť Anchor 0.0
; 0,0
.
Budem teda používať toto pozicovanie. Ak sa vám lepšie uvažuje a pracuje s iným, tak ho samozrejme používajte. Len budete musieť pri každom pozicovanie prísť na súradnice pre váš Anchor, aby bol výsledok rovnaký.
Pretože je pozíciovanie dôležité, pripravil som ešte ilustračný obrázok rôzneho nastavenia Anchor:
Pozadia
Presunieme sa do GameScene.swift
. Ako už vieme z prvej lekcie,
máme tu k dispozícii metódu didMove()
, ktorá je zavolaná vždy
na začiatku a môžeme v nej nastaviť všetko v scéne.
Podobne ako s viewDidLoad()
odporúčam vytvárať
pre nastavenie jednotlivých vecí v scéne oddelené metódy a tie potom volať
v didMove()
, aby sa jej telo čítalo ako zoznam príkazov. Vďaka
tomu oveľa ľahšie zistíte, čo má vlastne metóda na starosť. Vytvoríme
si teda novú metódu createBackground()
, v ktorej pozadí
vytvoríme. Vlastne skoro akýkoľvek objekt vo SpriteKit má za potomka triedu
SKNode
, ktorá slúži ako taký základný stavebný blok. My
budeme často používať SKSpriteNode
, ktorý je špecializovaná
na zobrazovanie 2D objektov.
Začneme teda jej vytvorením a použijeme náš obrázok ako textúru:
let background = SKSpriteNode(imageNamed: "background")
Teraz nastavíme vlastnosť zPosition
, čo je klasická
z
súradnice určujúce, v akom poradí sú na sebe objekty
"naskladané". Pozadie bude logicky najnižšie, takže mu dáme napr.
-5
.
background.zPosition = -5
Zostáva nastaviť pozíciu a pridať objekt do scény. Pozíciu musíme
nastaviť z dôvodu, že sme zmenili predvolený Anchor zo stredovej
(0.5
; 0.5
) na ľavý dolný roh, ale pozícia
akýchkoľvek ďalších SKNode
je stále predvolený, teda
(0.5
; 0.5
). Pozíciu teda posunieme o polovicu
šírky a o polovicu výšky scény a pomocou addChild()
pridáme
pozadí ako objekt scény:
background.position = CGPoint(x: size.width / 2, y: size.height / 2) addChild(background)
Teraz stačí createBackground()
zavolať v
didMove()
a hru už môžete zapnúť. Uvidíte pozadie.
Hráč
Máme pozadia a podobným štýlom pridáme do hry vesmírnu loď hráča.
Opäť si teda vytvoríme metódu setupPlayer()
, avšak samotný
objekt inicializujeme na úrovni triedy, aby sme k nemu mohli pristupovať:
let player = SKSpriteNode(imageNamed: "player")
A teraz už v tele metódy zatiaľ pridáme tieto riadky, ktoré hráča pridajú nadol doprostred:
player.position = CGPoint(x: size.width / 2, y: 120) addChild(player)
Ovládanie
S loďou hráčov budeme horizontálne hýbať pomocou ťahanie prsta. To je
intuitívne a na implementáciu jednoduchá metóda. Začneme v metóde
touchesMoved()
, ktorú sme síce pri našom čistení zmazali, ale
nie je problém ju pomocou pomocníka dostať späť:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { }
Metóda je zavolaná vždy, keď hráč pohne prstom po displeji a dostaneme sadu dotykov. Tu je najjednoduchšie vziať ten prvý a zistiť jeho umiestnenie v scéne:
guard let first = touches.first else { return } let touchPosition = first.location(in: self)
Potom už stačí len upraviť pozíciu hráča takto:
player.position.x = touchPosition.x
Pretože nesiahame na súradnicu y
, tak sa bude hráč
pohybovať len horizontálne. Môžete hru zapnúť a vyskúšať.
Vyjdenie z obrazovky a teleport
Sú tu dva menšie problémy. Hráč môže loď dostať zhruba z polovice mimo obrazovku, čo nie je práve pekné. Okrem toho môže využiť teleportu, keď sa prstom nedotkne priamo lodi.
Vyjdenie z obrazovky
Prvý problém vyrieši guard
pred nastavením nové pozície
hráča, jednoducho sa spýtame, či je nová súradnice x
väčší ako šírka lode a zároveň menšie ako
šířka scény - šířka lodi
:
guard touchPosition.x > player.size.width && touchPosition.x < size.width - player.size.width else { return }
Opäť môžete vyskúšať
Teleport
A teraz zamedzenie teleportu. Najjednoduchšie bude vytvorenie
bool
premenné, ktoré nám povie, či sa hráč dotkol lodi. Inak
mu pohyb nedovolíme. Vytvoríme teda premennú:
var shouldMovePlayer = false
A presunieme sa do metódy touchesBegan()
. Tu sa opäť opýtame
na prvý dotyk a pomocou dostupných metód zistíme, či sa hráč dotkol lodi.
Celé to bude vyzerať takto:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let first = touches.first else { return } let tapped = nodes(at: first.location(in: self)) shouldMovePlayer = tapped.contains(player) }
Metóda nodes(at: )
je veľmi užitočná. Zo zadanej pozície v
scéne nám vráti všetky objekty (teda SKNode
), ktoré sa na
danom mieste nachádzajú.
Potom už stačí upraviť touchesMoved()
a pridať na začiatok
ďalšej guard
, kde overíme pridanou bool
premennú:
guard shouldMovePlayer else { return }
A samozrejme nesmieme zabudnúť na situáciu, kedy hráč prestane jazdiť
prstom po displeji. V metóde touchesEnded()
nastavíme premennú
opäť na false
:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { shouldMovePlayer = false }
Môžete vyskúšať. Teraz už ide posúvať loď len pri priamom dotyku.
Časticové efekty
Na záver tejto lekcie si ukážeme, ako hru oživiť časticami. Tie nám neskôr poslúži k vytvoreniu explózií. Zatiaľ je využijeme na simulovanie "prachu" vo vesmíre, aby sme získali dojem, že sa hráč skutočne pohybuje.
Časticové efekty môžu znieť ako obtiažna časť vývoja hier, ale SpriteKit nám prácu s nimi podstatne uľahčuje. Primárne vďaka vizuálnemu editore a pripraveným šablónam.
Hviezdny prach
Pridajte si teda do projektu nový súbor a ako typ vyberte "SpriteKit
Particle File" a ako šablónu "Snow". Ako názov som zvolil
Space Dust
.
Na začiatok vyzerá východzí sneh celkom dobre. Padá smerom, ktorý chceme, takže nás čakajú skôr menšie úpravy.
Najskôr upravíme hodnotu "Position range" na 750
pre
x
(čo je šírka scény) a 0
pre y
. To
znamená, že sa častice budú objavovať sa súradnicou x
niekde
v rozmedzí 0
až 750
.
Ďalej som nastavil "Speed" na hodnoty 20
pre "Štart" a
0
pre "Range". Teda konštantnú rýchlosť. Častice som tiež
zmenšil nastavením "Scale" na 0.05
a "Range" na rovnakú
hodnotu.
Počet sa ovláda pomocou nastavenia "Emitter" úplne hore, kde som pre
"Birthrate" nastavil 20
. Ako posledný som nastavil "Lifetime" na
20
, aby častice nezmizli, kým sú vidieť na obrazovke.
Tu samozrejme zas platí, že hodnoty vyššie sú skôr odporúčané. Skúste si s nastavením pohrať a vytvoriť si častice vlastný
Pridanie častíc do scény
Teraz už stačí pridať častice do scény. Opäť začneme s metódou
createParticles()
. Pre častice máme špeciálnu
SKEmitterNode
, ktorú vytvoríme a odovzdáme ju náš súbor:
func createParticles() { if let spaceDust = SKEmitterNode(fileNamed: "SpaceDust") { spaceDust.zPosition = -1 spaceDust.position = CGPoint(x: size.width / 2, y: size.height) addChild(spaceDust) } }
Je to podobné, ako u pozadie a hráča. Vytvoríme objekt, nastavíme
zPosition
a position
tak, aby častice začínali
uprostred hornej hrany. Potom už len stačí pridať do scény.
Teraz môžete hru vyskúšať, bude o poznanie živšie.
AdvanceSimulationTime ()
Máme tu ale problém, pretože po spustení efekt nevyzerá dobre, pretože časticiam zaberie, než zaplní celú obrazovku.
Našťastie má SKEmitterNode
skvelú metódu, ktorá toto
rieši. Volá sa advanceSimulationTime()
a dovolí nám vlastne
"pretočiť" čas simulácie. Nastavil som hodnotu na 15
, tesne
pred addChild(spaceDust)
a po spustení výsledok vyzerá oveľa
lepšie.
Výsledok je veľmi pôsobivý:
Pokračovať budeme nabudúce, v lekcii Nepriatelia a ich pohyb vo SpriteKit .
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é 26x (119.84 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Swift