SpriteKit From Scratch Physik und Kollisionen

Einführung

In diesem Tutorial, der dritten Ausgabe der SpriteKit From Scratch-Serie, werfen wir einen detaillierten Einblick in die Simulationsfunktionen von SpriteKit für die Physik und deren Verwendung in Ihren 2D-SpriteKit-Spielen.

Für dieses Lernprogramm müssen Sie Xcode 7.3 oder höher ausführen. Dazu gehören Swift 2.2 und die iOS 9.3, tvOS 9.2 und OS X 10.11.4 SDKs.

Um zu folgen, können Sie entweder das Projekt verwenden, das Sie im vorherigen Tutorial erstellt haben, oder eine neue Kopie von GitHub herunterladen.

Die für das Spiel in dieser Serie verwendeten Grafiken finden Sie auf GraphicRiver. GraphicRiver ist eine großartige Quelle, um Grafiken und Grafiken für Ihre Spiele zu finden.

1. Physikwelten

Der erste Teil jeder Physik-Simulation in SpriteKit ist der PhysikWelt Eigenschaft der aktuellen Szene. Diese Eigenschaft ist ein SKPhysicsWorld Objekt, das Eigenschaften wie die Schwerkraft Ihrer Szene, die Geschwindigkeit der Physiksimulation und den Kontaktdelegierten definiert. Physikwelten können auch Verbindungen zwischen Objekten definieren, um effektiv mehrere Knoten an bestimmten Punkten miteinander zu verbinden.

Schwere

Für die Draufsicht Wenn wir ein Stilspiel dieser Serie erstellen, möchten wir den von SpriteKit bereitgestellten Standardwert für die Schwerkraft ändern. Die Standardgravitation ist für a vorgesehen Vorderansicht Spiel mit einem Wert von (0, -9,8) das simuliert die Schwerkraft der Erde, 0 Horizontalbeschleunigung und Abwärtsbeschleunigung von 9,8 m / s². Für unser Spiel brauchen wir 0 vertikale Schwerkraft, so dass das Auto nach dem Einstellen der physikalischen Eigenschaften nicht abwärts beschleunigt.

Öffnen MainScene.sks und klicken Sie auf den grauen Hintergrund, um die Szene auszuwählen. Als nächstes öffnen Sie die Attribute-Inspektor und ändern Schwere so dass sowohl die X und Komponenten sind auf gesetzt 0.

Es ist wichtig zu wissen, dass die Schwerkraft die einzige physikalische Welteigenschaft ist, die mit dem Szenen-Editor von Xcode geändert werden kann. Alle anderen Eigenschaften müssen programmgesteuert geändert werden.

Kontaktieren Sie den Delegierten

Damit das Spiel Kollisionen zwischen Objekten erkennen kann, müssen wir die Physikwelt der Szene einstellen contactDelegate Eigentum. Dieser Delegat kann ein beliebiges Objekt sein, das dem entspricht SKPhysicsContactDelegate Protokoll. Dieses Protokoll definiert zwei Methoden, didBeginContact (_ :) und didEndContact (_ :). Mit diesen Methoden können Sie Aktionen basierend auf den Objekten ausführen, die in der Szene kollidieren.

Um unseren Code zusammen zu halten, erstellen wir die MainScene Instanz einen eigenen Kontaktdelegierten. Öffnen MainScene.swift und bearbeiten Sie die MainScene Klassendefinition an die SKPhysicsContactDelegate Protokoll.

import UIKit import SpriteKit-Klasse MainScene: SKScene, SKPhysicsContactDelegate …

Im didMoveToView (_ :), wir setzen die MainScene Instanz als Kontaktdelegat der PhysikWelt Eigentum.

func didMoveToView überschreiben (view: SKView) … physicsWorld.contactDelegate = self

Wir werden die Methoden des implementieren SKPhysicsContactDelegate Protokoll später. Zuerst müssen wir die physikalischen Eigenschaften der Knoten in der Szene einstellen.

2. Körper der Physik

Jedem Knoten in SpriteKit, auf dem Sie Physik simulieren möchten, muss ein eindeutiger Knoten zugewiesen werden SKPhysicsBody Objekt. Physikkörper enthalten verschiedene Eigenschaften, darunter:

  • Masse
  • Dichte
  • Bereich
  • Reibung
  • Geschwindigkeit

In Ihren Spielen können Sie auch bis zu 32 eindeutige Kategorien definieren. Ein Physikkörper kann einer beliebigen Anzahl dieser Kategorien zugewiesen werden. Kategorien sind sehr nützlich, um zu bestimmen, welche Knoten in Ihrer Szene bei Kollisionen miteinander interagieren können.

In Physikkörpern werden diese Kategorien durch die vertreten categoryBitMask und collisionBitMask Eigenschaften, denen beide gegeben sind 0xFFFFFFFF Standardwert. Dies bedeutet, dass alle Knoten zu allen Kategorien gehören. Es ist wichtig zu beachten, dass in diesem Wert jede hexadezimale Ziffer steht F ist eine Kurzform und steht für die Zahl 15 in binären Ziffern (1111), von denen jede einer der 32 Kategorien entspricht, die Sie verwenden können.

Wenn zwei Knoten kollidieren, eine logische UND Die Bedienung wird am durchgeführt collisionBitMask und das categoryBitMask des ersten bzw. zweiten Körpers. Wenn das Ergebnis ein Wert ungleich Null ist, führt SpriteKit die Simulation auf den beiden Knoten aus, zu denen die Körper gehören.

Beachten Sie, dass dies UND Die Berechnung wird zweimal durchgeführt, wobei die beiden Körper ausgetauscht werden. Zum Beispiel:

  • Berechnung 1: bodyA.collisionBitMask & bodyB.categoryBitMask
  • Berechnung 2: bodyB.collisionBitMask & bodyA.categoryBitMask

Wenn Sie nicht wissen wie UND Operator funktioniert, dann ist hier ein sehr einfaches Beispiel in Swift geschrieben:

let mask1 = 0x000000FF let mask2 = 0x000000F0 let Ergebnis = Maske1 & Maske2 // Ergebnis = 0x000000F0

Das UND Der Operator bestimmt, welche Teile der Bitmasken gleich sind, und gibt einen neuen Bitmaskenwert zurück, der die übereinstimmenden Teile enthält.

Zu beachten ist, dass diese Bitmasken nur die SpriteKit-Seite der Physiksimulation betreffen und Sie nicht über Kollisionen informiert werden, die auf diese Weise erkannt werden. Dies bedeutet, dass Körper miteinander interagieren können, aber keine der Methoden des Kontaktdelegierten aufgerufen wird.

Damit diese Methoden ausgeführt werden können, müssen Sie a angeben contactTestBitMask für jeden Körper, der einen Wert ungleich Null erzeugt, wenn ein UND Operator wirkt auf sie ein. Für alle Physikkörper hat diese Bitmaske den Standardwert von 0x00000000 Das bedeutet, dass Sie nicht über Kollisionen informiert werden, an denen die Physik beteiligt ist.

Physik-Körper einschließlich ihrer verschiedenen Bitmasken können im Xcode-Szenen-Editor eingerichtet werden. Öffnen MainScene.sks, Wähle das Auto aus und öffne die Attribute-Inspektor zur Rechten. Scrollen Sie nach unten zu Physik-Definition Sektion.

weil Körpertyp ist eingestellt auf Keiner, Keine der physikalischen Eigenschaften ist sichtbar. Um dies zu ändern, müssen wir einstellen Körpertyp auf einen anderen Wert als Keiner. Es stehen drei Körpertypen zur Verfügung:

  • Begrenzungsrechteck
  • Begrenzungskreis
  • Alpha-Maske
Th

Diese drei physischen Körpertypen sind die häufigsten in SpriteKit. Begrenzendes Rechteck und Begrenzungskreis Erstelle eine Barriere um das Sprite, die in Physik-Simulationen verwendet wird. Dies bedeutet, dass das Sprite mit einem anderen Knoten kollidiert, wenn seine Begrenzungsform auf den Physikkörper eines anderen Knotens trifft.

Die Kante eines Begrenzungsrechtecks ​​entspricht genau der Größe des Knotens, die im Szeneneditor angezeigt wird. Wenn Sie auswählen Begrenzungskreis, Sie sehen jedoch einen dünnen hellblauen Kreis, der die Form des Begrenzungskreises darstellt.

Alpha-Maske arbeitet ein wenig anders und betrachtet die tatsächliche Bildtextur des Sprites, um die Kanten des physischen Körpers zu bestimmen. Dieser Körpertyp ist bei SpriteKit bei weitem der genaueste, kann jedoch einen großen Einfluss auf die Leistung Ihres Spiels haben, insbesondere wenn Sie Sprites mit komplexen Formen verwenden.

Für unser Spiel, da wir nur ein Auto-Sprite verwenden und unsere Szene nicht besonders komplex ist, werden wir das verwenden Alpha-Maske Körpertyp. Es ist nicht Es wird empfohlen, diesen Körpertyp für alle Sprites in Ihrer Szene zu verwenden, obwohl er am genauesten ist. Wenn Sie diese Option aus dem Dropdown-Menü auswählen, sollte eine hellblaue Linie um die Fahrzeugkante erscheinen.

Es ist wichtig zu beachten, dass andere Arten von Physikkörpern programmgesteuert erstellt werden können, z. B. Körper von CGPath Objekte sowie Kreise und Rechtecke in benutzerdefinierten Größen.

Immer noch im Attribute-Inspektor, Sie sollten jetzt mehr Optionen für Sie sehen Physik-Definition Sektion. Die einzige Eigenschaft, die wir ändern müssen, ist die Kontaktmaske. Ändern Sie diesen Wert auf einen Wert von 1.

Wenn die physische Karosserie des Autos eingerichtet ist, können wir einige Hindernisse in das Spiel einbauen, um mit dem Auto zu kollidieren.

3. Kollisionen erkennen

Bevor wir die Methoden des implementieren SKPhysicsContactDelegate Protokoll, müssen wir einige Hindernisse für das Auto hinzufügen, um zu vermeiden. Dazu spawnen wir alle drei Sekunden ein neues Hindernis vor dem Auto und positionieren das Hindernis in einer zufälligen Spur.

Öffnen MainScene.swift und fügen Sie eine Importanweisung für die hinzu GameplayKit Framework, damit wir die von GameplayKit bereitgestellten Zufallszahlengeneratoren verwenden können.

GameplayKit importieren

Fügen Sie als Nächstes die folgende Methode hinzu MainScene Klasse:

func spawnObstacle (timer: NSTimer) if player.hidden timer.invalidate () return let spriteGenerator = GKShuffledDistribution (niedrigsterWert: 1, höchsterWert: 2) let obstacle = SKSpriteNode (imageNamed: "hindacle \") ") obstacle.xScale = 0.3, obstacle.yScale = 0.3 let physicsBody = SKPhysicsBody (circleOfRadius: 15) physicsBody.contactTestBitMask = 0x00000001 = physicsBody.pinned = true Differenz = CGFloat (85.0) var x: CGFloat = 0 let laneGenerator = GKShuffledDistribution (niedrigster Wert: 1, höchster Wert: 3) switch laneGenerator.nextInt () Fall 1: x = Mittelpunkt - Differenzfall 2: x = Mittelpunktfall 3: x = center + difference Voreinstellung: fatalError ("Nummer außerhalb von [1, 3] generiert") obstacle.position = CGPoint (x: x, y: (player.position.y + 800)) addChild (Hindernis)

Diese Methode wird alle drei Sekunden aufgerufen. Lassen Sie uns es aufteilen, um zu sehen, was los ist. Wenn der aktuelle Spielerknoten ausgeblendet ist, was wahr ist, wenn das Auto auf ein Hindernis trifft, wird der Timer ungültig und das Auftauchen von Hindernissen gestoppt.

Wir erhalten eine Zufallszahl zwischen 1 und 2, Verwenden Sie diese Option, um einen Sprite-Knoten mit einem der beiden im Projekt verfügbaren Hindernis-Sprites zu erstellen. Wir ändern dann die Skala des Hindernisses, so dass sie klein genug sind, damit das Auto herumfahren kann.

Als Nächstes erstellen wir einen Physikkörper für dieses neue Hindernis mit einem Kreis mit einem Radius von fünfzehn und eine Kontaktmaske von 0x00000001. Legen wir fest gepinnt zu wahr und allowRotation zu falsch damit das Hindernis an Ort und Stelle bleibt und sich nicht bewegt. Der Physikkörper wird dann dem Hindernis zugeordnet.

Wir erzeugen eine weitere Zufallszahl zwischen 1 und 3 um zu bestimmen, auf welcher Spur sich das Hindernis befinden soll, geben Sie dem Hindernis die berechnete Position und fügen Sie es der Szene hinzu.

Beachten Sie, dass der horizontale Unterschied, 85, benutzt in spawnObstacle (_ :) unterscheidet sich von der, die beim Bewegen des Autos verwendet wird, 70. Wir tun dies, um dem Auto ein bisschen mehr Raum zu geben, um sich zwischen Hindernissen zu bewegen.

Wenn die Logik für das Hindernis vorhanden ist, können wir den folgenden Code am Ende des Befehls hinzufügen didMoveToView (_ :) Methode.

func didMoveToView überschreiben (view: SKView) … let timer = NSTimer (timeInterval: 3.0, target: self, Selector: #selector (spawnInObstacle (_ :)), userInfo: nil, wiederholt: true) NSRunLoop.mainRunLoop (). addTimer (Timer, fürMode: NSRunLoopCommonModes) let camera = SKCameraNode () self.camera = camera camera.position = CGPoint (x: center, y: player.position.y + 200) let moveForward = SKAction.moveBy (CGVectorMake (0, 100) ), duration: 1.0) camera.runAction (SKAction.repeatActionForever (moveForward)) addChild (camera) player.xScale = 0,4; player.yScale = 0.4 // Macht das Auto kleiner, um besser zwischen Hindernissen zu passen.

Wir erstellen einen Timer zum Ausführen spawnObstacle (_ :) alle drei Sekunden und fügen Sie es der Hauptlaufschleife hinzu. Wir erstellen auch eine SKCameraNode als die Kamera für die Szene zu fungieren und sie dem zuzuordnen Kamera Eigentum der Szene. Dadurch wird die Szene aus Sicht des Kameraknotens gerendert. Beachten Sie, dass die Kamera horizontal und etwas oberhalb des Fahrzeugs zentriert ist.

Wir fügen der Kamera auch eine identische Aktion hinzu, damit sie mit dem Auto in einer Reihe bleibt. Wir fügen die Kamera als untergeordneten Knoten der Szene hinzu, wie jeder andere reguläre Knoten. Zu guter Letzt verkleinern wir das Auto, damit es etwas besser zwischen die Hindernisse passt.

Der letzte Teil für die Kollisionserkennung implementiert eines der beiden SKPhysicsContactDelegate Protokollmethoden. In unserem Fall werden wir das implementieren didBeginContact (_ :) Methode, da wir benachrichtigt werden möchten, sobald das Auto auf ein Hindernis trifft. Fügen Sie die folgende Methode dem hinzu MainScene Klasse.

func didBeginContact (Kontakt: SKPhysicsContact) if contact.bodyA.node == Spieler || contact.bodyB.node == player player.hidden = true player.removeAllActions () Kamera? .removeAllActions ()

Sie können sehen, dass diese Methode eine hat SKPhysicsKontakt Parameter übergeben. Dieses Objekt enthält wichtige Informationen zur Kollision, einschließlich der Richtung, des Impulses und der beteiligten Objekte.

In diesem Code geht es nur darum, welche Knoten an der Kollision beteiligt sind. Wir prüfen, ob einer von ihnen das Auto war, und wenn dies wahr ist, verstecken Sie das Auto in der Szene und beenden die Bewegung des Autos und der Kamera.

Erstellen und starten Sie Ihre App und spielen Sie Ihr Spiel. Sie werden sehen, dass, wenn Sie auf ein Hindernis stoßen, das Auto verschwindet und die Szene sich nicht mehr bewegt.

Fazit

Sie sollten nun wissen, wie Sie Physikkörper für die Knoten in Ihrer Szene einrichten und diese verwenden, um realistische Physik zu simulieren. Sie sollten sich auch mit der Einrichtung der Kollisionserkennung in Ihrer Szene vertraut machen, indem Sie einen Kontaktdelegierten definieren und Kontakttest-Bitmasken für die Knoten zuweisen, von denen Sie erwarten, dass sie miteinander kollidieren.

Im nächsten Tutorial von SpriteKit From Scratch werden wir uns die erweiterten visuellen Funktionen von SpriteKit ansehen, darunter Partikelsysteme, Lichtquellen und Filter.

Wie immer sollten Sie Ihre Kommentare und Rückmeldungen in den nachstehenden Kommentaren hinterlassen.