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

6. diel - Pridanie fyziky a detekcia kolízií vo SpriteKit

V predchádzajúcej lekcii, Nepriatelia strieľa späť a dokonca laserom vo SpriteKit , sme v našej iOS hre vo Swift skončili vyzbrojením nepriateľov laserom a pridali zvukové efekty. Naše strely ale stále nič nerobia a práve to napravíme v tomto tutoriálu.

Fyzika vo SpriteKit

Je na čase predstaviť si, ako funguje fyzika vo SpriteKit. Nám pomôže s detekciou kolízií, ale využiť sa dá pre rad ďalších vecí, pretože napríklad môžete veľmi ľahko upravovať gravitáciu herného sveta. Tá je v predvolenom stave nastavená tak, aby emuloval Zem, takže predmety, ktoré majú fyzické telo, automaticky padajú k zemi a odrážajú sa od seba.

Pomocou gravitácie môžete ľahko implementovať ovládanie v hrách pomocou nakláňania zariadení. Jednoducho podľa naklonenie upravíte gravitácii a SpriteKit sa postará o zvyšok.

Aktivácia fyziky

Fyzika už na pozadí našej hry funguje, ale žiadny z našich objektov nemá nastavené physicsBody, takže sa na neho nevzťahuje. Ako prvý teda musíme nastaviť physicsBody pre všetky naše objekty, aby sme mohli neskôr detekovať kolízie týchto objektov.

Player

Začneme napríklad u hráčov (súbor Player.swift) a na koniec init() pridáme tento riadok:

physicsBody = SKPhysicsBody(texture: texture, size: texture.size())

To stačí, aby fyzika začala na model hráča realisticky pôsobiť. Fyzikálne reprezentáciu vytvárame z textúry, čo je síce náročnejšie na výkon, ale budeme mať tzv. "Pixel-perfect" kolízie. Laserová strela sa bude musieť skutočne presne dotknúť lodi hráča, aby bola započítaná.

Ešte v triede Player zostaneme a rovno nastavíme physicsBody tiež raketám v metóde createMissiles():

missile1.physicsBody = SKPhysicsBody(rectangleOf: missile1.size)
missile2.physicsBody = SKPhysicsBody(rectangleOf: missile2.size)

Pre ukážku som tu použil vytvorenie fyzikálne reprezentácie ako obdĺžnika, čo je pri detekcii kolízií oveľa rýchlejší ako vytvorenie z textúry. Výkonovo by nebol problém opäť použiť textúru, chcem ale ukázať aj ďalší spôsob :-) V momente, kedy budete mať v hre hromadu fyzikálnych objektov, sa už oplatí premýšľať, akým štýlom physicsBody vytvoriť.

Enemy

Presunieme sa do triedy Enemy a vykonáme tu prakticky to isté. Najprv v metóde create():

enemy.physicsBody = SKPhysicsBody(texture: texture, size: texture.size())

A pre laserovú strelu:

laser.physicsBody = SKPhysicsBody(rectangleOf: laser.texture!.size())

laser.texture je Optional, pretože SKSpriteNode ide vytvoriť len z farby bez textúry. My ale vieme, že sme textúru použili a výkričník tak nie je problém.

Skúška fyziky

Teraz môžete hru vyskúšať a pozrieť sa, ako sa vlastne zmenila.

Ak ste všetko nastavili správne, videli ste názornú ukážku simulovanej gravitácie. My samozrejme nechceme, aby všetky lode spadli mimo hraciu plochu ...

Vypnutie gravitácie

Fyziku v našej vesmírnej hre síce využijeme, ale gravitácia tu nedáva moc zmysel. Takže ju v didMove() vypneme:

physicsWorld.gravity = .zero

Vlastnosť gravity je typu CGVector, ktorý sa používa pre reprezentáciu smeru a intenzity. V predvolenom stave je gravitácia nastavená na vektor CGVector(dx: 0, dy: -9.8).

Hru môžete zapnúť a radovať sa, že naše objekty nepadajú nekonečne nadol. Lenže teraz do seba všetko naráža a rôzne sa otáča. To hneď vyriešime pomocou bitovej masky, až budeme kolízie konfigurovať.

Druhou možnosťou by bolo nastaviť vlastnosť physicsBody.isDynamic, ktorá zabráni, aby sa objekt hýbal, či už vplyvom gravitácie alebo kolízie. Tu vlastnosť nevyužijeme, hodí sa ale vedieť, na čo slúži. Dajte zároveň pozor na to, že kolízie nebudú fungovať, ak budú mať oba objekty nastavené idDynamic na false.

Konfigurácia kolízií

Nám vlastne bude stačiť, aby nám SpriteKit povedal, keď dôjde ku kolízii medzi raketou a nepriateľom a tiež ku kolízii medzi laserom a lodí hráča. Pre konfiguráciu budeme potrebovať kategórii kolidovaného objektu. Mohli použiť obyčajná čísla, pripravíme si ale enum, nech je výsledok prehľadnejšie.

Enum

Vytvoríme si teda enum pomenovaný treba ObjectType v súbore GameScene.swift, ale mimo definíciu triedy GameScene:

enum ObjectType: UInt32 {
    case player = 1
    case missile = 2
    case enemy = 4
    case laser = 8
}

Ako typ sme použili UInt32, pretože práve ten používa SpriteKit pre definíciu masiek. Hodnota je vždy dvojnásobok predchádzajúceho, aby išlo tieto hodnoty pre danú masku kombinovať (keď si predstavíte čísla binárne, je player 0001, missile 0010, enemy 0100 a laser 1000, player a zároveň laser by teda teoreticky mohol byť 1001, aj keď to tu nedáva zmysel). Kombináciou by sme využili, ak by sme napríklad chceli, aby dochádzalo ku kolízii medzi hráčom a laserom a tiež medzi hráčom a nepriateľom, čo v našej hre ale nenastane.

Teraz musíme tieto hodnoty správne priradiť našim objektom. K tomu si ale konečne predstavme ako bitové masky vo SpriteKit fungujú.

Vysvetlenie bitových masiek

Objekty vo SpriteKit majú bitovej masky celkom 3:

  • categoryBitMask nám vlastne len určuje, aký typ je daný objekt.
  • Ďalej nastavujeme contactTestBitMask, ktorá slúži na to, aby sme povedali SpriteKit o kolíziách s akou kategóriou nám má dať vedieť.
  • Tretia maska, collisionBitMask, určuje, od akej kategórie sa má automaticky objekt odraziť, ako by došlo ku kolízii v skutočnom svete. My ju všade nastavíme na 0, aby do seba veci nenarážali a rôzne sa nám nehýbali mimo našu kontrolu.

Ak vám v budúcnosti nebudú v nejakej hre fungovať kolízie, mali by bitové masky byť prvá vec, ktorú budete kontrolovať a prípadne skúšať upraviť.

Nastavenie bitových masiek objektom

Začneme v triede Player a konstruktoru init():

physicsBody?.categoryBitMask = ObjectType.player.rawValue
physicsBody?.contactTestBitMask = ObjectType.laser.rawValue
physicsBody?.collisionBitMask = 0

Ďalej musíme tieto masky nastaviť pre rakety:

missile1.physicsBody?.categoryBitMask = ObjectType.missile.rawValue
missile1.physicsBody?.contactTestBitMask = ObjectType.enemy.rawValue
missile1.physicsBody?.collisionBitMask = 0
missile2.physicsBody?.categoryBitMask = ObjectType.missile.rawValue
missile2.physicsBody?.contactTestBitMask = ObjectType.enemy.rawValue
missile2.physicsBody?.collisionBitMask = 0

Môže vás lákať využiť metódu copy() a jednoducho nastavené physicsBody prvej rakety skopírovať do druhej. To ale nebude fungovať, pretože metódy copy() v tomto prípade vytvorí novú inštanciu SKPhysicsBody a nedôjde k preneseniu nastavených vlastností.

Zostáva nastavenia pre nepriateľov:

enemy.physicsBody?.categoryBitMask = ObjectType.enemy.rawValue
enemy.physicsBody?.contactTestBitMask = ObjectType.missile.rawValue
enemy.physicsBody?.collisionBitMask = 0

A laser:

laser.physicsBody?.categoryBitMask = ObjectType.laser.rawValue
laser.physicsBody?.contactTestBitMask = ObjectType.player.rawValue
laser.physicsBody?.collisionBitMask = 0

Získanie informácií o kolíziách

Keď teraz hru zapnete, malo by všetko fungovať ako by sme nič nové nepridali. Zostáva už však len minimum, aby sme získavali informácie o kolíziách.

V prvom rade musíme našej GameScene pridať protokol SKPhysicsContactDelegate a v didMove() ho nastaviť:

physicsWorld.contactDelegate = self

O kolíziách sa dozvieme skrze metódu:

func didBegin(_ contact: SKPhysicsContact) {
        print("Contact!")
}

Pre vyskúšanie som doplnil print(). Keď teraz hru zapneme, môžeme sledovať výpis Contact! ak raketa trafí nepriateľa alebo laser loď hráča.

V budúcej lekcii, Dokončenie kolízií vo SpriteKit , už môžeme pridať explózie po kontakte a tiež odstrániť zničené nepriateľov a rozhodnúť sa, ako veľmi bude hráč penalizovaný za zásah laserom.


 

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é 9x (954.48 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Swift

 

Predchádzajúci článok
Nepriatelia strieľa späť a dokonca laserom vo SpriteKit
Všetky články v sekcii
Tvorba iOS hier vo Swift
Preskočiť článok
(neodporúčame)
Dokončenie kolízií vo SpriteKit
Článok pre vás napísal Filip Němeček
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity