Lekce 3 - Nepřátelé a jejich pohyb ve SpriteKit
V předchozí lekci, Pozadí, ovládání hráče a částicové efekty ve SpriteKit, jsme vytvořili pozadí, přidali loď hráče včetně ovládání a celé to okořenili pomocí částicových efektů.
Teď je čas přidat hordy pohybujících se nepřátel.
Vlna nepřátel
Vlny nepřátel se budou lehce hýbat, aby byla hra živější a hráč neměl tak jednoduché trefování protivníků. V první řadě tedy musíme vymyslet, jak nejlépe vlnu nepřátel vytvořit. Určitě nechceme nepřátele pozicovat manuálně a pro každého z třeba osmi vymýšlet souřadnice.
Nejlepší bude vytvořit si pomocnou funkci na vytvoření celé nepřátelské vlny s využitím trošku té náhody. Něco podobného se nám bude hodit také v případě, že budeme chtít zvýšit obtížnost a přidat další nepřátele.
Textury nepřátel
Ještě, než začneme, přetáhněte si do Assets.xcassets
obrázky nepřátel. Já použil ty tři z první lekce a jmenují se
enemyBlack1
, enemyBlack2
a
enemyBlack3
:
Pokud máte jiné názvy nebo jiný počet obrázků, je s tím nutné
počítat, až budeme vytvářet SKSpriteNode
objekty.
SKNode
Protože budeme chtít se všemi nepřáteli hýbat, nepřidáme je přímo
do naší scény, ale vytvoříme si instanci SKNode
, kterou
využijeme jako kotvu. Díky tomu můžeme potom rozhýbat tuto jednu
SKNode
a tím se budou hýbat všichni nepřátelé
souběžně.
Jako první si tedy vytvoříme instanci na úrovni naší
GameScene
třídy:
let enemyAnchor = SKNode()
Nastavení kotvy
Opět si vytvoříme pomocnou metodu setupEnemyAnchor()
a
nezapomeneme ji zavolat v didMove()
. Zatím jen přidá
enemyAnchor
do scény a nastaví pozici:
func setupEnemyAnchor() { enemyAnchor.position = CGPoint(x: 0, y: size.height - 200) addChild(enemyAnchor) }
Generování vln
To bylo jednoduché, teď potřebujeme kód pro generování vln nepřátel.
To už bude složitější. Začneme vytvořením metody
createEnemyWave()
. Zatím bude brát jako parametr
enemyCount
typu Int
, tedy kolik nepřátel chceme
vytvořit.
Nyní potřebujeme vymyslet, jak nepřátele hezky rovnoměrně rozmístit
vedle sebe. Po nějakém tom experimentování jsem došel sice k celkem
obsáhlé metodě, na druhou stranu ale obsahuje minimum "magických čísel" a
je docela flexibilní. Kód níže tedy všechen patří postupně do metody
createEnemyWave()
.
Prototyp
Jako první si vytvoříme prototyp protivníka a pro snadnější
pozicování upravíme jeho anchorPoint
:
let enemyTemplate = SKSpriteNode(imageNamed: "enemyBlack1") enemyTemplate.anchorPoint = CGPoint(x: 0, y: 0.5)
Samozřejmě si za "enemyBlack1"
doplňte název vašeho
obrázku pro nepřátele. Později uděláme náhodný výběr, abychom měli
také nějakou tu variabilitu.
Výpočty
Dále si pro výpočet uložíme šířku nepřítele, šířku všech ve vlně a také konstantu pro rozestup mezi nimi:
let enemySize = enemyTemplate.size.width let enemiesSize = enemySize * CGFloat(enemyCount) let enemySpacing: CGFloat = 15
Už máme přípravy skoro hotové. Ještě potřebujeme zbývající
šířku, abychom mohli vypočítat správné odsazení a nepřátele zarovnat.
Prostě od šířky celé scény odečteme sumu šířek nepřátel a mezer mezi
nimi (mezer je o jednu méně). A rovnou si připravíme proměnnou
xOffset
pro výpočet souřadnice, ta udává kolik je vlevo před
vlnou nepřátel volného místa:
let remainingSpace = size.width - enemiesSize - CGFloat(enemyCount - 1) * enemySpacing let xOffset = remainingSpace / 2
Cyklus
Teď se můžeme přesunout k cyklu, který vytvoří nepřátele, nastaví
jim korektní pozici a přidá je do scény za pomoci
enemyAnchor
:
for i in 0 ..< enemyCount { }
Následující kód tedy bude součástí cyklu. Nejdříve uděláme kopii z
enemyTemplate
:
let newEnemy = enemyTemplate.copy() as! SKSpriteNode
as!
je zde v pořádku, protože přesně víme, s
jakým objektem máme co do činění, takže se přetypování určitě
povede.
Zbývá finální výpočet souřadnice x
daného nepřítele a
její nastavení:
let xPosition = xOffset + CGFloat(i) * (enemySize + enemySpacing) newEnemy.position = CGPoint(x: xPosition, y: 50)
O korektní odsazení se ve výpočtu stará xOffset
a potom za
pomoci i
a velikosti nepřítele společně s mezerou získáme
finální souřadnici. Pro y
je zatím dočasná hodnota pro první
vlnu nepřátel.
Přidání nového nepřítele do vlny
Teď už jen stačí přidat pomocí addChild()
nepřítele
naší kotvě enemyAnchor
:
enemyAnchor.addChild(newEnemy)
A metodu zavolat v didMove()
createEnemyWave(enemyCount: 5)
Můžeme se přesvědčit, jak vypadá výsledek:
Pokud máte obrázky nepřátel, které jsou natočené dopředu
jako loď hráče, bude nutné je otočit. Můžete to udělat rovnou s pomocí
SpriteKit a to nastavením vlastnosti zRotation
na
.pi
, což obrázek otočí o 180°. Zde to ale bude problém,
protože jsme změnili anchorPoint
kvůli snadnějšímu
pozicování a podle něj se bude SKSpriteNode
rovněž otáčet.
Lepší bude tedy provést otočení v grafickém editoru.
Rozpohybování s pomocí SKAction
Nyní si představíme prakticky nepostradatelnou třídu
SKAction
, která nám pomůže hru rozpohybovat. Je koncipovaná
jako takové stavební bloky, kdy každý dělá jednu malou věc a můžeme je
řetězit za sebou nebo spouštět společně.
My zatím SKAction
použijeme k tomu, aby se nepřátelé
začali hýbat. Protože máme připravený enemyAnchor
, tak není
třeba je rozhýbávat jednotlivě.
startEnemyMovement()
Vytvoříme si metodu startEnemyMovement()
a rovnou ji zavoláme
v didMove()
. Následuje implementace této metody.
Nejdříve vytvoříme akci pro pohyb doprava:
let moveRight = SKAction.moveBy(x: 35, y: 0, duration: 0.5)
Kde jsem vzal čísla? Odhad a experimentování, co vypadá v této situaci nejlépe. Pohyb doleva bude ještě jednodušší, protože prostě otočíme tuto akci:
let moveLeft = moveRight.reversed()
Teď z těchto akcí vytvoříme sekvenci, což je opět typ
SKAction
. Je to vlastně takový seznam, který nám dovolí
skládat akce za sebe:
let moveSequence = SKAction.sequence([moveRight, moveLeft, moveLeft, moveRight])
moveLeft
je dvakrát za sebou, protože první akce vrátí
objekt do původní polohy a druhá ho již posune doleva.
Co dál? SKAction
můžeme "spouštět" na jakékoliv
SKNode
. Takže na enemyAnchor
spustíme
SKAction.forever
, která bude neustále opakovat naši sekvenci
pohybu:
enemyAnchor.run(SKAction.repeatForever(moveSequence))
A naši nepřátelé se hýbou:
Můžete opět vyzkoušet a případně si zkusit navrhnout vlastní
pohybovou sekvenci. Třeba zapojením souřadnice y
.
V příští lekci, Střílení raket a další částicové efekty ve SpriteKit, se budeme věnovat střelbě hráče.
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 10x (143.54 kB)
Aplikace je včetně zdrojových kódů v jazyce Swift