Eine Einführung in GameplayKit Teil 1

Einführung

Neben allen neuen Funktionen und Frameworks in iOS 9 und OS X El Capitan, Mit den diesjährigen Veröffentlichungen hat Apple auch ein völlig neues Framework für Spieleentwickler geschaffen, GameplayKit. Mit den vorhandenen Grafik-APIs (SpriteKit, SceneKit und Metal), die es einfach machen, auf iOS und OS X großartig aussehende Spiele zu erstellen, hat Apple jetzt GameplayKit veröffentlicht, um das Erstellen von Spielen zu vereinfachen abspielen Gut. Dieses neue Framework enthält viele Klassen und Funktionen, mit deren Hilfe Sie komplexe Logik leicht zu Ihren Spielen hinzufügen können.

In diesem ersten Tutorial werde ich Ihnen zwei wichtige Aspekte des GameplayKt-Frameworks vermitteln:

  • Entitäten und Komponenten
  • Zustandsmaschinen

Voraussetzungen

Dieses Tutorial setzt voraus, dass Sie ausgeführt werden Xcode 7 auf OS X Yosemite oder später. Obwohl dies nicht erforderlich ist, wird empfohlen, dass ein physisches Gerät ausgeführt wird iOS 9 Da Sie beim Testen des SpriteKit-basierten Spiels, das in diesem Lernprogramm verwendet wird, eine viel bessere Leistung erzielen.

1. Erste Schritte

Sie müssen zunächst das Starterprojekt für diese Serie von Tutorials von GitHub herunterladen. Wenn Sie dies getan haben, öffnen Sie das Projekt in Xcode und führen Sie es entweder auf dem iOS-Simulator oder auf Ihrem Gerät aus.

Sie werden sehen, dass es ein sehr einfaches Spiel ist, in dem Sie einen blauen Punkt steuern und auf der Karte navigieren. Wenn Sie mit einem roten Punkt kollidieren, verlieren Sie zwei Punkte. Wenn Sie mit einem grünen Punkt kollidieren, erhalten Sie einen Punkt. Wenn Sie mit einem gelben Punkt kollidieren, wird Ihr eigener Punkt für einige Sekunden eingefroren.

In dieser Phase ist es ein sehr einfaches Spiel, aber im Verlauf dieser Tutorialserie und mit Hilfe von GameplayKit werden wir viel mehr Funktionen und Gameplay-Elemente hinzufügen.

2. Entitäten und Komponenten

Der erste wichtige Aspekt des neuen GameplayKit-Frameworks ist ein Code-Strukturierungskonzept, das auf basiert Entitäten und Komponenten. Dies ermöglicht es Ihnen, dem Entwickler, allgemeinen Code zu schreiben, der von vielen verschiedenen Objekttypen in Ihrem Spiel verwendet wird, während er gut organisiert und überschaubar bleibt. Das Konzept der Entitäten und Komponenten soll den üblichen vererbungsbasierten Ansatz zur gemeinsamen Nutzung der Funktionalität zwischen Objekttypen beseitigen. Der einfachste Weg, dieses Konzept zu verstehen, besteht in einigen Beispielen. Stellen Sie sich das folgende Szenario vor:

Sie bauen ein Turmverteidigungsspiel mit drei Haupttypen von Türmen, Feuer, Eis, und Heilen. Die drei Türme würden einige gemeinsame Daten wie Gesundheit, Größe und Stärke teilen. Ihre Feuer- und Eistürme müssen in der Lage sein, auf eintreffende Feinde zu zielen, auf die Sie schießen können, während Ihr Heilturm dies nicht tut. Alles, was Ihr Heilerturm tun muss, ist, Ihre anderen Türme innerhalb eines bestimmten Radius zu reparieren, wenn sie Schaden erleiden.

Im Hinblick auf dieses grundlegende Spielemodell möchten wir Ihnen zeigen, wie Ihr Code mit Hilfe von organisiert werden kann Erbe Struktur:

  • Ein Elternteil Turm Klasse mit gängigen Daten wie Gesundheit, Größe und Stärke.
  • FireTowerIceTower, und Heilerturm Klassen, die von der erben würden Turm Klasse.
  • In dem Heilerturm Klasse, Sie haben die Logik, die für die Heilung Ihrer anderen Türme in einem bestimmten Radius verantwortlich ist.

Bisher ist diese Struktur in Ordnung, aber es tritt jetzt ein Problem auf, wenn Sie die Zielfunktion der Feuer- und Eistürme implementieren müssen. Kopieren Sie einfach den gleichen Code in beide FireTower und IceTower Klassen? Wenn Sie Änderungen vornehmen müssen, müssen Sie Ihren Code an mehreren Stellen ändern, was mühsam und fehleranfällig ist. Was passiert außerdem, wenn Sie einen neuen Tower-Typ hinzufügen möchten, für den diese Targeting-Funktion erforderlich ist? Kopieren Sie es und fügen Sie es ein drittes Mal ein?

Der beste Weg scheint es zu sein, diese Targeting-Logik in das übergeordnete Element zu integrieren Turm Klasse. Auf diese Weise können Sie nur eine Kopie des Codes haben, die nur an einer Stelle bearbeitet werden muss. Das Hinzufügen dieses Codes hier würde jedoch die Turm Klasse viel größer und komplizierter als es sein muss, wenn nicht alle seine Unterklassen diese Funktionalität benötigen. Wenn Sie auch mehr gemeinsam genutzte Funktionen zwischen Ihren Tower-Typen hinzufügen möchten, wird Ihr Turm Die Klasse würde allmählich größer werden, was die Arbeit erschweren würde.

Wie Sie sehen, ist es zwar möglich, ein Spielmodell zu erstellen Erbe, es kann sehr schnell und leicht unorganisiert werden und schwer zu handhaben sein.

Nun wollen wir sehen, wie dieses Spielmodell mit strukturiert werden könnte Entitäten und Komponenten:

  • Wir würden schaffen FireTowerIceTower, und Heilerturm Entitäten. Für weitere Turmtypen, die Sie später hinzufügen möchten, können weitere Entitäten erstellt werden.
  • Wir würden auch eine erstellen BasicTower Komponente, die Gesundheit, Größe, Stärke usw. enthalten würde.
  • Um die Heilung Ihrer Türme in einem bestimmten Radius zu bewältigen, fügen Sie eine hinzu Heilung Komponente.
  • EIN Targeting Die Komponente würde den Code enthalten, der erforderlich ist, um ankommende Feinde anzugreifen.

Mit GameplayKit und dieser Struktur hätten Sie dann für jeden Tower-Typ in Ihrem Spiel einen eindeutigen Entitätstyp. Zu jeder einzelnen Entität können Sie die gewünschten Komponenten hinzufügen. Zum Beispiel:

  • Ihre FireTower und IceTower Entitäten hätten jeweils eine BasicTower und Targeting damit verknüpfte Komponente.
  • Ihre Heilerturm Entität hätte sowohl eine BasicTower und ein Heilung Komponente.

Wie Sie sehen, ist Ihr Spielmodell durch die Verwendung einer entitäts- und komponentenbasierten Struktur jetzt wesentlich einfacher und vielseitiger. Ihre Targeting-Logik muss nur einmal geschrieben werden und verlinkt nur die Entitäten, die sie benötigt. Ebenso können Ihre grundlegenden Tower-Daten immer noch problemlos zwischen allen Ihren Türmen ausgetauscht werden, ohne dass Sie all Ihre anderen Funktionen in Anspruch nehmen müssen.

Eine weitere tolle Sache bei dieser entitäts- und komponentenbasierten Struktur ist, dass Komponenten jederzeit zu Entitäten hinzugefügt und daraus entfernt werden können. Wenn Sie beispielsweise möchten, dass Ihre Heal-Türme unter bestimmten Bedingungen deaktiviert werden, können Sie einfach das entfernen Heilung Komponente von Ihrem Unternehmen, bis die richtigen Bedingungen erfüllt sind. Wenn Sie möchten, dass einer Ihrer Feuertürme eine vorübergehende Heilungsfähigkeit erhält, können Sie einfach eine hinzufügen Heilung Komponente zu Ihrem FireTower Entität für eine bestimmte Zeitspanne.

Nachdem Sie mit dem Konzept einer entity- und komponentenbasierten Spielmodellstruktur vertraut sind, erstellen wir eine in unserem eigenen Spiel. In Xcodes Dateiinspektor, finde das Entitäten Ordner innerhalb Ihres Projekts. Der Einfachheit halber gibt es bereits drei Entitätsklassen, aber Sie erstellen jetzt eine neue Entität von Grund auf.

Wählen Datei> Neu> Datei… oder drücken Sie Befehl-N eine neue Klasse erstellen. Stellen Sie sicher, dass Sie das auswählen Kakao-Touch-Klasse Vorlage aus der iOS> Quelle Sektion. Benennen Sie die Klasse Spieler und mache es eine Unterklasse von GKEntity.

Sie werden sehen, dass Xcode sofort nach dem Öffnen Ihrer neuen Datei einen Fehler anzeigt. Fügen Sie die folgende Importanweisung unter dem vorhandenen hinzu, um das Problem zu beheben UIKit importieren Aussage:

GameplayKit importieren

Geh zurück zu PlayerNode.swift und fügen Sie die folgende Eigenschaft hinzu PlayerNode Klasse:

var entity = Spieler ()

Navigieren Sie anschließend zu Komponenten Ordner in Ihrem Xcode-Projekt und erstellen Sie eine neue Klasse wie zuvor. Benennen Sie dieses Mal die Klasse FlashingComponent und mache es eine Unterklasse von GKComponent Wie nachfolgend dargestellt.

Die Komponente, die Sie gerade erstellt haben, übernimmt das visuelle Aufblinken unseres blauen Punkts, wenn er von einem roten Punkt getroffen wird und sich in seinem unverwundbaren Zustand befindet. Ersetzen Sie den Inhalt von FlashingComponent.swift mit den folgenden:

import UIKit import SpriteKit importieren GameplayKit-Klasse FlashingComponent: GKComponent var nodeToFlash: SKNode! func startFlashing () let fadeAction = SKAction.sequence ([SKAction.fadeOutWithDuration (0.75), SKAction.fadeInWithDuration (0.75)]) nodeToFlash.runAction (SKAction.repeatActionForever (fadeAction)) mitTaste: "flash". removeActionForKey ("flash")

Die Implementierung enthält lediglich einen Verweis auf eine SKNode Objekte und Wiederholungen ein- und ausblenden, solange die Komponente aktiv ist.

Geh zurück zu GameScene.swift und fügen Sie den folgenden Code irgendwo in der didMoveToView (_ :) Methode:

// Hinzufügen einer Komponente let flash = FlashingComponent () flash.nodeToFlash = playerNode flash.startFlashing () playerNode.entity.addComponent (flash)

Wir schaffen ein FlashingComponent Objekt und richten Sie es so ein, dass es am Punkt des Spielers blinkt. Die letzte Zeile fügt die Komponente dann zur Entität hinzu, damit sie aktiv bleibt und ausgeführt wird.

App erstellen und ausführen Sie werden jetzt sehen, dass Ihr blauer Punkt langsam wiederholt ein- und ausgeblendet wird.

Bevor Sie fortfahren, löschen Sie den Code, den Sie gerade hinzugefügt haben didMoveToView (_ :) Methode. Später fügen Sie diesen Code jedoch erst wieder hinzu, wenn Ihr blauer Punkt seinen unverwundbaren Zustand erreicht.

3. Zustandsmaschinen

In GameplayKit bieten Zustandsmaschinen eine Möglichkeit, Aufgaben auf der Grundlage der aktuellen Aufgaben zu erkennen und auszuführen Zustand eines bestimmten Objekts. Aus dem früheren Beispiel der Turmverteidigung lassen sich einige mögliche Zustände für jeden Turm ableiten Aktiv, Deaktiviert, und Zerstört. Ein großer Vorteil von Zustandsmaschinen ist, dass Sie angeben können, in welche Zustände sich ein anderer Zustand verschieben kann. Mit den drei oben genannten Beispielzuständen können Sie die Zustandsmaschine mithilfe einer Zustandsmaschine folgendermaßen einrichten:

  • ein turm kann werden Deaktiviert wann Aktiv und umgekehrt
  • ein turm kann werden Zerstört wann entweder Aktiv oder Deaktiviert
  • ein Turm kann nicht werden Aktiv oder Deaktiviert sobald es war Zerstört

Im Spiel für dieses Tutorial halten wir es sehr einfach und haben nur eine normal und unverwundbar Zustand.

In deinem Projekt Zustandsmaschine Ordner erstellen, erstellen Sie zwei neue Klassen. Benenne sie Normalzustand und Unverletzlicher Zustand jeweils beide eine Unterklasse der GKState Klasse.

Ersetzen Sie den Inhalt von NormalState.swift mit den folgenden:

import UIKit importieren SpriteKit importieren GameplayKit-Klasse NormalState: GKState var node: PlayerNode init (withNode: PlayerNode) node = withNode überschreibt die Funktion func isValidNextState (stateClass: AnyClass) -> Bool switch stateClass Fall ist der Standardwert InvulnerableState.Type: : false zurückgeben func didEnterWithPreviousState überschreiben (previousState: GKState?) wenn _ = vorherigerState as? InvulnerableState node.entity.removeComponentForClass (FlashingComponent) node.runAction (SKAction.fadeInWithDuration (0.5))

Das Normalzustand Klasse enthält Folgendes:

  • Es implementiert einen einfachen Initialisierer, um einen Verweis auf den Knoten des aktuellen Spielers zu behalten.
  • Es hat eine Implementierung für die isValidNextState (_ :) Methode. Die Implementierung dieser Methode gibt einen booleschen Wert zurück, der angibt, ob die aktuelle Zustandsklasse in die vom Methodenparameter bereitgestellte Zustandsklasse verschoben werden kann.
  • Die Klasse enthält auch eine Implementierung für die didEnterWithPreviousState (_ :) Rückrufmethode. In der Implementierung der Methode überprüfen wir, ob der vorherige Status der war Unverletzlicher Zustand Status und entfernen Sie, falls zutreffend, die blinkende Komponente aus der Entität des Players.

Jetzt offen InvulnerableState.swift und ersetzen Sie den Inhalt durch Folgendes:

import UIKit importieren GameplayKit-Klasse InvulnerableState: GKState var node: PlayerNode init (withNode: PlayerNode) node = withNode überschreiben func isValidNextState (stateClass: AnyClass) -> Bool switch stateClass Fall ist NormalState.Type: return true default: return false override func didEnterWithPreviousState (vorherigerStatus: GKState?) wenn _ = vorherigerStatus als? NormalState // Komponente hinzufügen let flash = FlashingComponent () flash.nodeToFlash = Knoten flash.startFlashing () node.entity.addComponent (flash)

Das Unverletzlicher Zustand Klasse ist dem sehr ähnlich Normalzustand Klasse. Der Hauptunterschied besteht darin, dass Sie beim Eintritt in diesen Status die blinkende Komponente zur Entität des Players hinzufügen, anstatt sie zu entfernen.

Nun, da Ihre Statusklassen beide vollständig und offen sind PlayerNode.swift noch einmal und fügen Sie die folgenden Zeilen hinzu PlayerNode Klasse:

var stateMachine: GKStateMachine! func enterNormalState () self.stateMachine.enterState (NormalState)

Dieses Code-Snippet fügt eine neue Eigenschaft hinzu PlayerNode Klasse und implementiert eine bequeme Methode, um zum Normalzustand zurückzukehren.

Jetzt offen GameScene.swift und am Ende des didMoveToView (_ :) fügen Sie die folgenden zwei Zeilen hinzu:

playerNode.stateMachine = GKStateMachine (Status: [NormalState (withNode: playerNode)), InvulnerableState (withNode: playerNode)]) playerNode.stateMachine.enterState (NormalState)

In diesen beiden Codezeilen erstellen wir eine neue GKStateMachine mit den zwei Zuständen und sagen Sie ihm, dass Sie die Normalzustand.

Ersetzen Sie abschließend die Implementierung des handleContactWithNode (_ :) Methode der GameScene Klasse mit der folgenden Implementierung:

func handleContactWithNode (contact: ContactNode) wenn der Kontakt PointsNode NSNotificationCenter.defaultCenter (). postNotificationName ("updateScore", object: self, userInfo: ["score": 1]) ist, wenn der Kontakt RedEnemyNode && playerNode.stateMachine ist. aktuellen Zustand! ist NormalState NSNotificationCenter.defaultCenter (). postNotificationName ("updateScore", object: self, userInfo: ["score": -2]) playerNode.stateMachine.enterState (InvulnerableState) playerNode.performSelector ("enterNormalState", withObject: nil, afterDelay: 5.0) else wenn der Kontakt YellowEnemyNode && playerNode.stateMachine.currentState ist! ist NormalState self.playerNode.enabled = false contact.removeFromParent ()

Wenn der blaue Punkt des Spielers mit einem roten Feindpunkt kollidiert, betritt der Spieler den Unverletzlicher Zustand Status für fünf Sekunden und kehren Sie dann zurück in die Normalzustand Zustand. Wir prüfen auch den aktuellen Status des Spielers und führen nur dann eine feindliche Logik durch, wenn dies der Fall ist Normalzustand Zustand.

Erstellen und starten Sie Ihre App ein letztes Mal und bewegen Sie sich auf der Karte, bis Sie einen roten Punkt finden. Wenn Sie mit dem roten Punkt kollidieren, sehen Sie, dass Ihr blauer Punkt in den unverwundbaren Zustand übergeht und fünf Sekunden lang blinkt.

Fazit

In diesem Tutorial habe ich Ihnen zwei der wichtigsten Aspekte des GameplayKit-Frameworks vorgestellt, Entitäten und Komponenten, und Zustandsmaschinen. Ich habe Ihnen gezeigt, wie Sie Entitäten und Komponenten verwenden können, um Ihr Spielmodell zu strukturieren und alles zu organisieren. Die Verwendung von Komponenten ist eine sehr einfache Möglichkeit, Funktionen zwischen Objekten in Ihren Spielen zu teilen.

Ich habe Ihnen auch die Grundlagen von Zustandsmaschinen aufgezeigt, wie Sie festlegen können, zu welchen Zuständen ein bestimmter Zustand übergehen kann, sowie die Ausführung von Code, wenn ein bestimmter Zustand eingegeben wird.

Bleiben Sie dran für den zweiten Teil dieser Serie, in dem wir dieses Spiel auf eine andere Ebene bringen werden, indem Sie künstliche Intelligenz hinzufügen, die als AI bezeichnet wird. Die KI ermöglicht es gegnerischen Punkten, den Spieler anzugreifen und den besten Weg zu finden, um den Spieler zu erreichen.

Wenn Sie Kommentare oder Fragen haben, lassen Sie sie wie folgt in den Kommentaren.