IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
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í.

Lekce 2 - Pozadí, ovládání hráče a částicové efekty ve SpriteKit

V předchozí lekci, Úvod do tvorby iOS her s frameworkem SpriteKit, jsme si představili SpriteKit včetně struktury projektu a nachystali textury pro vesmírnou střílečku.

Nyní se pustíme do budování naší hry.

Nakopírování textur

Jako první krok je třeba nakopírovat naše obrázky do Assets.xcassets v projektu a ideálně zvolit nějaké výstižné a jednoduché názvy. My si zvolíme background pro pozadí a player pro loď hráče.

Pozicování ve SpriteKit

Začneme s vytvořením pozadí. Než si pozadí přidáme do naší scény, potřebujeme si vysvětlit, jak funguje souřadnicový systém SpriteKit. Ve výchozím stavu totiž nezačíná v levém horním rohu jako UIKit.

Když si otevřete GameScene.sks, tak napravo v Attributes inspektoru můžete vidět informace o naší scéně. Nás zajímá položka "Anchor". Je to vlastně taková virtuální kotva ve scéně, podle které se budou umisťovat další prvky.

Ve výchozím stavu je nastavena na X: 0.5 a Y: 0.5. To znamená střed scény. V praxi se používá buď toto nastavení nebo X: 0.0 a Y: 0.0, což znamená levý dolní roh.

Rozhodnutí jaký Anchor zvolit je dost podstatné a nejde udělat jednoznačné doporučení. Záleží totiž na tom, jak je vaše hra koncipovaná. Pokud bychom tvořili hru, ve které bude obrazovka celá herní aréna a hráč se nebude pohybovat mimo, tak je nejlogičtější ponechat právě 0.5;0.5 a vše nastavovat vzhledem ke středu. Naše hra bude mít ve spodní části loď hráče, iluzi letu vesmírem a nepřátele v horní části obrazovky. Z pohledu této hry dává smysl použít Anchor 0.0;0,0.

Budu tedy používat toto pozicování. Pokud se vám lépe uvažuje a pracuje s jiným, tak ho samozřejmě používejte. Jen budete muset při každém pozicování přijít na souřadnice pro váš Anchor, aby byl výsledek stejný.

Protože je pozicování důležité, připravil jsem ještě ilustrační obrázek různého nastavení Anchor:

Anchors ve SpriteKit - SpriteKit - Tvorba iOS her ve Swift

Pozadí

Přesuneme se do GameScene.swift. Jak již víme z první lekce, máme zde k dispozici metodu didMove(), která je zavolána vždy na začátku a můžeme v ní nastavit všechno ve scéně.

Podobně jako s viewDidLoad() doporučuji vytvářet pro nastavení jednotlivých věcí ve scéně oddělené metody a ty poté volat v didMove(), aby se její tělo četlo jako seznam příkazů. Díky tomu mnohem snadněji zjistíte, co má vlastně metoda na starost. Vytvoříme si tedy novou metodu createBackground(), ve které pozadí vytvoříme. Vlastně skoro jakýkoliv objekt ve SpriteKit má za potomka třídu SKNode, která slouží jako takový základní stavební blok. My budeme často používat SKSpriteNode, jenž je specializovaná na zobrazování 2D objektů.

Začneme tedy jejím vytvořením a použijeme náš obrázek jako texturu:

let background = SKSpriteNode(imageNamed: "background")

Nyní nastavíme vlastnost zPosition, což je klasická z souřadnice určující, v jakém pořadí jsou na sobě objekty "naskládané". Pozadí bude logicky nejníže, takže mu dáme např. -5.

background.zPosition = -5

Zbývá nastavit pozici a přidat objekt do scény. Pozici musíme nastavit z důvodu, že jsme změnili výchozí Anchor ze středové (0.5;0.5) na levý dolní roh, ale pozice jakýchkoliv dalších SKNode je stále výchozí, tedy (0.5;0.5). Pozici tedy posuneme o polovinu šířky a o polovinu výšky scény a pomocí addChild() přidáme pozadí jako objekt scény:

background.position = CGPoint(x: size.width / 2, y: size.height / 2)
addChild(background)

Nyní stačí createBackground() zavolat v didMove() a hru již můžete zapnout. Uvidíte pozadí.

SpriteKit - Tvorba iOS her ve Swift

Hráč

Máme pozadí a podobným stylem přidáme do hry vesmírnou loď hráče. Opět si tedy vytvoříme metodu setupPlayer(), ovšem samotný objekt inicializujeme na úrovni třídy, abychom k němu mohli přistupovat:

let player = SKSpriteNode(imageNamed: "player")

A nyní již v těle metody zatím přidáme tyto řádky, které hráče přidají dolů doprostřed:

player.position = CGPoint(x: size.width / 2, y: 120)
addChild(player)

Ovládání

S lodí hráče budeme horizontálně hýbat pomocí tažení prstu. To je intuitivní a na implementaci jednoduchá metoda. Začneme v metodě touchesMoved(), kterou jsme sice při našem čistění smazali, ale není problém ji pomocí nápovědy dostat zpět:

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
}

Metoda je zavolána vždy, když hráč pohne prstem po displeji a dostaneme sadu dotyků. Zde je nejjednodušší vzít ten první a zjistit jeho umístění ve scéně:

guard let first = touches.first else { return }
let touchPosition = first.location(in: self)

Potom již stačí jen upravit pozici hráče takto:

player.position.x = touchPosition.x

Protože nesaháme na souřadnici y, tak se bude hráč pohybovat jen horizontálně. Můžete hru zapnout a vyzkoušet.

SpriteKit - Tvorba iOS her ve Swift

Vyjetí z obrazovky a teleport

Jsou tu dva menší problémy. Hráč může loď dostat zhruba z poloviny mimo obrazovku, což není zrovna hezké. Kromě toho může využít teleportu, když se prstem nedotkne přímo lodi.

Vyjetí z obrazovky

První problém vyřeší guard před nastavením nové pozice hráče, prostě se zeptáme, jestli je nová souřadnice x větší než šířka lodi a zároveň menší než šířka scény - šířka lodi:

guard touchPosition.x > player.size.width && touchPosition.x < size.width - player.size.width else { return }

Opět můžete vyzkoušet :-)

Teleport

A nyní zamezení teleportu. Nejjednodušší bude vytvoření bool proměnné, které nám řekne, jestli se hráč dotkl lodi. Jinak mu pohyb nedovolíme. Vytvoříme tedy proměnnou:

var shouldMovePlayer = false

A přesuneme se do metody touchesBegan(). Zde se opět zeptáme na první dotek a pomocí dostupných metod zjistíme, jestli se hráč dotkl lodi. Celé to bude vypadat 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)
}

Metoda nodes(at: ) je velmi užitečná. Ze zadané pozice ve scéně nám vrátí všechny objekty (tedy SKNode), které se na daném místě nacházejí.

Potom už stačí upravit touchesMoved() a přidat na začátek další guard, kde ověříme přidanou bool proměnnou:

guard shouldMovePlayer else { return }

A samozřejmě nesmíme zapomenout na situaci, kdy hráč přestane jezdit prstem po displeji. V metodě touchesEnded() nastavíme proměnnou opět na false:

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        shouldMovePlayer = false
}

Můžete vyzkoušet. Teď už jde posouvat loď jen při přímém dotyku.

Částicové efekty

Na závěr této lekce si ukážeme, jak hru oživit částicemi. Ty nám později poslouží k vytvoření explozí. Zatím je využijeme na simulování "prachu" ve vesmíru, abychom získali dojem, že se hráč skutečně pohybuje.

Částicové efekty mohou znít jako obtížná část vývoje her, ale SpriteKit nám práci s nimi podstatně ulehčuje. Primárně díky vizuálnímu editoru a připraveným šablonám.

Hvězdný prach

Přidejte si tedy do projektu nový soubor a jako typ vyberte "SpriteKit Particle File" a jako šablonu "Snow". Jako název jsem zvolil Space Dust.

Na začátek vypadá výchozí sníh docela dobře. Padá směrem, který chceme, takže nás čekají spíše menší úpravy.

Nejdříve upravíme hodnotu "Position range" na 750 pro x (což je šířka scény) a 0 pro y. To znamená, že se částice budou objevovat se souřadnicí x někde v rozmezí 0750.

Dále jsem nastavil "Speed" na hodnoty 20 pro "Start" a 0 pro "Range". Tedy konstantní rychlost. Částice jsem rovněž zmenšil nastavením "Scale" na 0.05 a "Range" na stejnou hodnotu.

Počet se ovládá pomocí nastavení "Emitter" úplně nahoře, kde jsem pro "Birthrate" nastavil 20. Jako poslední jsem nastavil "Lifetime" na 20, aby částice nezmizely, dokud jsou vidět na obrazovce.

Zde samozřejmě zas platí, že hodnoty výše jsou spíše doporučené. Zkuste si s nastavením pohrát a vytvořit si částice vlastní :-)

Přidání částic do scény

Nyní již stačí přidat částice do scény. Opět začneme s metodou createParticles(). Pro částice máme speciální SKEmitterNode, kterou vytvoříme a předáme ji náš soubor:

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é, jako u pozadí a hráče. Vytvoříme objekt, nastavíme zPosition a position tak, aby částice začínaly uprostřed horní hrany. Potom už jen stačí přidat do scény.

Nyní můžete hru vyzkoušet, bude o poznání živější.

advanceSimula­tionTime()

Máme tu ale problém, protože po spuštění efekt nevypadá dobře, jelikož částicím zabere, než zaplní celou obrazovku.

Naštěstí má SKEmitterNode skvělou metodu, která tohle řeší. Jmenuje se advanceSimulationTime() a dovolí nám vlastně "přetočit" čas simulace. Nastavil jsem hodnotu na 15, těsně před addChild(spaceDust) a po spuštění výsledek vypadá mnohem lépe.

Výsledek je velmi působivý:

Částicový efekt v SpriteKit pro iOS - SpriteKit - Tvorba iOS her ve Swift

Pokračovat budeme příště, v lekci Nepřátelé a jejich pohyb ve SpriteKit.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 26x (119.84 kB)
Aplikace je včetně zdrojových kódů v jazyce Swift

 

Předchozí článek
Úvod do tvorby iOS her s frameworkem SpriteKit
Všechny články v sekci
SpriteKit - Tvorba iOS her ve Swift
Přeskočit článek
(nedoporučujeme)
Nepřátelé a jejich pohyb ve SpriteKit
Článek pro vás napsal Filip Němeček
Avatar
Uživatelské hodnocení:
1 hlasů
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity