Ze sceny do kodu

28 listopada 2017

SpriteKit

Cześć!
Witam Cię powonie, tym razem w 3 wpisie dotyczącym tworzenia gier 🎮 2D na platformę iOS.
Seria ta jest wprowadzeniem do programowania mobilnych gier w oparciu o framework SpriteKit. Jeśli nie programowałeś w nim wcześniej, zaczęcam do lektury całej serii:

Dzisiaj nadszedł czas, aby po okresie nauki edytora, budowania scen itp. przejść wreszcie do rzeczy i ubrudzić sobie ręce kodem. Dziś postaram się przekazać Ci wiedzę dotyczącą odwoływania się do elementów z kodu, tworzenia obiektów w kodzie, wykrywania akcji oraz podstawowych animacji. Jest co robić, i co kodować 😁👉💻 zatem zaczynamy!

Odwołania do elementów interfejsu

W drugim wspisie tej serii pisałem o budowaniu SKScene, czyli sceny w edytorze w Xcode. Jak pamiętasz, każdemu elementowi dodawanemu do naszej sceny nadawaliśmy nazwy (parametr Name). Te nazwy teraz posłużą nam do odwołania się do tych elementów w kodzie.

Przypominam Ci, żebyś ucząc się realizował jakiś konkretny projekt. To sprawi, że będziesz bardziej zmotywowany do nauki i lepiej przyswoisz nowo poznaną wiedzę z zakresu programowania gier na iOS.

Na początku tworzę nowy projekt, a następnie dodaję mój pierwszy sprite do mojej sceny. Nadaję mu także unikalną nazwę element.

Element na Scenie - SpriteKit

Następny korok, to porządek w naszej klasie kontrolera. Jeżeli korzystałeś z generatora projektu, Twoja klasa GameScene.swift posiada metodę didMove oraz szereg innych, wygenerowanych przez Xcode metod. Żeby zrobić trochę porządku, usuwam wszystkie metody poza metodą didMove (która jest czymś na wzór ViewDidLoad w UIKit) oraz metody update(_ currencTime: TimeInterval). Metodę didMove czyścimy.

Teraz chciałbym odwołać się do mojego elementu i np. pokolorować go na zielono. Aby odwołać się do elelemtu interfejsu, muszę odwołać się do childNode mojej SKScene. Będzie to wyglądało następująco:


override func didMove(to view: SKView) {
    if let element = self.childNode(withName: "element") as? SKSpriteNode{
        element.color = UIColor.green
    }
}

Efekt jest następujący:

Pokolorowany element na zielono

Ok, może nie jest to coś niesamowicie spektakularnego, ale od czegoś trzeba zacząć 😅. Skoro umiesz już odnosić się do elementów interfejsu, możemy przejść dalej.

Dodawanie elementów z poziomu kodu

Teraz pokażę Ci, w jaki sposób dodajemy elementy interfejsu z poziomu kodu Swift. Dodałem sobie w tym celu teksturę 8-bitowego ludzika do folderu assets.

Będzie to nasz player, dlatego tworzę instancje naszego ludzika jako zmienną typu – oczywiście – SKSpriteNode:

var player: SKSpriteNode?

Zatem, tworzymy metodę createPlayer() którą wywołamy skolei w metodzie didMove:


    var player: SKSpriteNode?
    
    func createPlayer() {
        player = SKSpriteNode(imageNamed: "mario")
        player?.position = CGPoint(x: 10, y: self.size.height / 2)
        player?.size = CGSize(width: 40, height: 60)
        
        self.addChild(player!)
        
    }
    
    override func didMove(to view: SKView) {
        createPlayer()
    }

Słowo komentarza – Ustaliłem pozycję gracza na dokładnie środek ekranu (CGPoint(x: self.size.width / 2, y: self.size.height / 2)), rozmiar naszego sprite’a na 40/60.
Na koniec najważniejsze – dodanie gracza do drzewa sceny jako potomka, z użyciem metody self.addChild(_ node:SKNode).

Efekt jest taki, że oto po kompilacji i uruchomieniu na urządzeniu, mamy Mario na środku ekranu!

Mario na środku ekranu

Wykrywanie akcji

Czas na przechwytywanie akcji użytkownika. Załóżmy, że po przyciśnięciu przycisku chcemy, aby Mario przeniósł się o konkretną odległość w prawą stronę ekranu. Mogę to oczywiście zrobić na kilka sposobów. Po pierwsze – mogę poruszać Mario w prawo za każdym razem, jak użytkownik dotknie ekranu. Takie akcje znane są z gier typu FlappyBird, kiedy to dotknięcie dowolnej części ekranu powoduje uniesienia ptaszka… no wiecie o co chodzi 😅… do góry…

Anyway… metody do tego powinieneś znać już z UIKit. Kiedy chcesz np. spowodować usunięcie klawiatury po kliknięciu poza pole do wpisywania tekstu, używasz zapewne metody touchesBegan(). I tak w SpriteKit jest zupełnie podobnie:


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

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

}

Jeżeli chcemy, aby Mario poruszał się w prawo, kiedy użytkownik trzyma paluch 👉📱 na ekranie, wystarczy że napiszemy funkcję poruszania ludzika i wywołamy ją w metodzie touchesBegan. Do poruszania obiektów w SpriteKit używa się klasy SKAction (dokładnie będę o tym pisał w kolejnym wpisie tej serii). Tworzymy zatem metode goRight() a w niej umieszczamy nasze akcje:


func goRight() {
    let go = SKAction.moveBy(x: 3, y: 0, duration: 0.01)
    let repeatAction = SKAction.repeatForever(go)
    player?.run(repeatAction)
}

Jak pamiętasz z poprzednich części tej serii, w edutorze SKScene możemy tworzyć animacje oraz zapętlać je. To samo możemy powtórzyć w kodzie Swift, używając metody statycznej repeatForever(_ SKAction). Po co to tutaj? Żeby Mario poruszał się w prawo do momentu, aż użytkownik zabierze palec z ekranu. Wywołujemy metodę w funkcji touchesBegan().

Aha – jenda ważna rzecz nim rzucisz się w wir testowania. Jest jeszcze druga metoda dotycząca akcji dotyku – touchesEnded. Odpowiada ona – jak sama nazwa wskazuje 😅 – za akcje puszczenia ekranu. Tam dorzucamu taką oto linijkę:


override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    player?.removeAllActions()
}

To spowoduje usunięcie wszystkich akcji i pętli z akcjami ze sprite’a, którym jest nasz Mario. Inaczej po naciśnięciu na ekran Mario będzie lazł w prawo bez zatrzymania, nawet jeśli użytkownik puści ekran. Ok, test… 💪😎. Wszystko pięknie!

Konkluzje

Ok, mamy to!
Dzisiejszy wpis pozwolił Ci zrozumieć podstawy dodawania elementów widoku bezpośrednio z kodu, odnoszenie się z wnętrza kodu do elementów dodanych w edytorze, a także zachłysnąłeś się podstawami poruszania i animacji obiektów. Jest dobrze! Ale to oczywiście nie koniec zabawy ze SpriteKit! 🎮

Jeżeli czytasz tą serię i dopiero uczysz się SpriteKit oraz programowania gier na iOS, to po przeczytaniu dzisiejszego wpisu polecam Ci poeksperymentować z różnymi elementami i sposobem poruszania ich po scenie. Np. dla ćwiczenia stwórz na dole ekranu takie centrum nawigacyjne dla swojego player’a, dodaj tekstury odpowiadające za strzałki w górę, prawo, lewo i dół. Spróbuj wykryć naciśnięcie ich przez użytkownika, a następnie poruszenie player’a w odpowiednią stronę. O, takie zadanko 😅.
Kod do tego zadanka podrzucę na GIT’a pod koniec tygodnia, przed publikacją nowego wpisu.

PRACTICE, PRACTICE, PRACTICE!

A tymczasem, bardzo serdecznie Ci dziękuję że czytasz ten artykuł oraz że (mam nadzieję) regularnie zaglądasz na tego bloga. Daj znać jak Ci się tu podoba – w komentarzu pod dowolnym postem, na twitterze, instagramie, grupie na facebook’u lub tradycyjnie napisz mi maila 😁.

Dzięki jeszcze raz i do następnego!
@jkornat

Kategorie: SpriteKitSwift

4 Komentarze

Kevin · Listopad 28, 2017 o 13:16

Hi Jakub,

I saw you tweeting about games and I thought I’d check out your website. I really like it. Looks like Jakub has come a long way!

Have you thought of building a mailing list? I think people would really like to be signed up to what you have to share.

Good job on the social buttons, social media is so powerful these days

You should consider installing an SEO plugin like Yoast or something, theres loads of good free ones.

Also if you want to earn some extra money I found G2A to work out quite nicely give it a shot. https://www.g2a.com/r/weeklysaleoct

    viewDidLoad() · Listopad 29, 2017 o 06:15

    Wpisy dotyczące SpriteKit są naprawdę dobre, od podstaw i z przykładami
    Super robota, fajnie ze zaczynaja pojawiać się takie materiały po Polsku 🙂

      Jakub Kornatowski

      Jakub Kornatowski · Listopad 29, 2017 o 07:47

      Cześć!
      Dzięki wielkie za pozytywny komentarz!😁 Fajnie że się podoba!!
      Oczywiście lecę z tematem dalej – będą pojawiały się też inne serie i wpisy, także zachęcam i zapraszam do regularnych odwiedzin 💪

      Trzymaj się!

    Jakub Kornatowski

    Jakub Kornatowski · Listopad 29, 2017 o 07:54

    Thanks man!
    Apreciate! But now I’m using AllInOne SEO pack.
    About mailing list – I’m thinking about it because few people was asking about it.

    Anyway, thanks for your comment. I’m also thinking for creating english version of this blog, because I get so much feedback that there are english readers interested in.

    Take care!

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *