Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
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 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:

Obrázek nepřítele 1 - SpriteKit - Tvorba iOS her ve Swift Obrázek nepřítele 2 - SpriteKit - Tvorba iOS her ve Swift Obrázek nepřítele 3 - SpriteKit - Tvorba iOS her ve Swift

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:

Generování nepřátel v iOS hře v SpriteKit a Swift - SpriteKit - Tvorba iOS her ve Swift

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ě.

startEnemyMove­ment()

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:

Pohyb nepřátel ve SpriteKit v iOS hře - SpriteKit - Tvorba iOS her ve Swift

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

 

Předchozí článek
Pozadí, ovládání hráče a částicové efekty ve SpriteKit
Všechny články v sekci
SpriteKit - Tvorba iOS her ve Swift
Přeskočit článek
(nedoporučujeme)
Střílení raket a další částicové efekty 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