iOS 8 Wat is er nieuw in SpriteKit, deel 2

Deze tutorial geeft een overzicht van de nieuwe functies van het SpriteKit-framework die werden geïntroduceerd in iOS 8. De nieuwe functies zijn ontworpen om het gemakkelijker te maken om geavanceerde game-effecten te ondersteunen en omvatten ondersteuning voor aangepaste OpenGL ES fragment shaders, belichting, schaduwen, geavanceerde nieuwe fysica-effecten en -animaties en integratie met SceneKit. In deze zelfstudie leert u hoe u deze nieuwe functies implementeert.

Serie-indeling

Deze serie is opgesplitst in twee tutorials en behandelt de belangrijkste nieuwe functies van het SpriteKit-framework. In het eerste deel bekijken we shaders, belichting en schaduwen. In het tweede deel zal ik het hebben over fysica en SceneKit-integratie.

Hoewel elk deel van deze serie op zichzelf staat, adviseer ik om stap voor stap de nieuwe functies van het SpriteKit-framework goed te begrijpen. Na het lezen van beide delen, kunt u zowel eenvoudige als geavanceerdere games maken met behulp van de nieuwe functies van het SpriteKit-framework.

Download het Xcode-project dat we in het vorige artikel van GitHub hebben gemaakt als je het wilt volgen.

1. Natuurkunde

In iOS 8 introduceerde SpriteKit nieuwe fysische kenmerken, zoals per-pixel fysica, beperkingen, inverse kinematica en fysica velden.

Kinematica is het proces van het berekenen van de 3D-positie van het uiteinde van een gekoppelde structuur, gezien de hoeken van alle gewrichten. Inverse Kinematics (IK) doet het tegenovergestelde. Gezien het eindpunt van de constructie, welke hoeken moeten de voegen maken om dat eindpunt te bereiken? De volgende afbeelding verduidelijkt deze concepten.

Met SpriteKit gebruikt u sprites om verbindingen weer te geven die de ouder-kindrelatie gebruiken om een ​​gezamenlijke hiërarchie te maken. Voor elke relatie definieert u de beperkingen van de inverse kinematica op elk gewricht en bepaalt u de minimale en maximale rotatiehoek daartussen. Merk op dat elke verbinding rond zijn ankerpunt roteert.

Stap 1: Inverse Kinematics (IK)

Open de PhysicsSceneEditor en voeg de kroket-o.png sprite naar de gele rechthoek. Selecteer de sprite en wijzig deze Naam in de SKNode Inspector naar Wortel. Stel de Fysica Definitie Lichaamstype naar Geen.

Voeg een tweede sprite toe, wood.png en verander zijn Naam naar FirstNode. Verander de Ouder veld naar Root. verhuizing FirstNode door het rechts van te plaatsen Wortel en wijzig het formaat om een ​​rechthoek te maken zoals hieronder wordt getoond. Stel de Fysica Definitie Lichaamstype naar Geen.

Het resultaat zou op de volgende scène moeten lijken.

Merk op dat, wanneer u een sprite-knoop selecteert, een witte cirkel in het midden verschijnt. Die cirkel vertegenwoordigt het ankerpunt van de sprite-node waarrond elke rotatie wordt uitgevoerd.

Stap 2: voeg meer sprites toe

Volg de vorige stappen en voeg nog twee sprites toe.

Eerste Sprite

  • Nog een toevoegen kroket-o.png sprite.
  • Verander zijn Naam SecondNode.
  • Verander zijn Ouder naar FirstNode.
  • Plaats het rechts van FirstNode.
  • Verander zijn Fysica Definitie Lichaamstype naar Geen.

Tweede Sprite

  • Nog een toevoegen wood.png sprite.
  • Verander zijn Naam veld ThirdNode.
  • Verander zijn Ouder naar SecondNode.
  • Plaats het rechts van SecondNode.
  • Pas het formaat aan om een ​​rechthoek te maken.
  • Verander zijn Fysica Definitie Lichaamstype naar Geen.

Het resultaat zou op de volgende scène moeten lijken.

Stap 3: Bewerken en simuleren

Om de gezamenlijke verbindingen, interacties en beperkingen te testen, hoeft u uw project niet te bouwen en uit te voeren. Xcode biedt twee modi, bewerken en simuleren.

De simulatiemodus biedt een realtime testomgeving, terwijl de bewerkingsmodus wordt gebruikt om uw scène te maken en te bewerken. Tot nu toe hebben we in de bewerkingsmodus gewerkt. Merk op dat alle wijzigingen die u aanbrengt in de simulatiemodus niet worden opgeslagen.

Onderaan de scène-editor kun je zien in welke modus je momenteel werkt. Als de onderste balk van de scène-editor wit is, ben je in de bewerkingsmodus. Een blauwe achtergrond geeft aan dat u zich in de simulatiemodus bevindt. Klik op het label in de balk onderaan om tussen de twee modi te schakelen.

Wijzig de modus om de sprites FirstNode, SecondNode en ThirdNode te simuleren en te selecteren. U kunt meerdere sprites selecteren door op te drukken Commando.

Druk vervolgens op Shift-Control-Click en verplaats de sprites rond in de scène. Het resultaat is dat de sprite-knooppunten animeren en roteren. De rotatie is echter raar en moet worden gecorrigeerd.

Stap 4: IK Beperkingen

Schakel terug naar de bewerkingsmodus en voeg een paar beperkingen toe aan de sprite-knooppunten. Selecteer elk sprite-knooppunt en wijzig de eigenschappen ervan als volgt.

Selecteer de Wortel en SecondNode sprite-knooppunten en stel de IK beperkingen Max. Hoek naar 0. Selecteer de FirstNode en ThirdNode sprite-knooppunten en instellen  Ankerpunt X naar 0 en IK beperkt de maximale hoek naar 90.

Door deze eigenschappen te wijzigen, veranderen de positie en de grootte van de sprite-knooppunten. Nadat u de beperkingen hebt toegevoegd, past u hun grootte en positie handmatig aan en schakelt u over naar de simulatiemodus om de nieuwe beperkingen te testen die we hebben toegevoegd.

De onderstaande schermafbeelding illustreert de juiste constraints-configuratie.

Stap 5: Magnetisch veldknooppunt

Magnetische velden zijn ook nieuw in SpriteKit. Laten we eens kijken hoe dit werkt door een magnetisch veld toe te voegen aan de natuurkundige scène. Open PhysicsScene.m en een instantievariabele genaamd magneticFieldNode van type SKFieldNode.

@implementation PhysicsScene SKFieldNode * magneticFieldNode; 

In de didMoveToView: methode, we configureren eerst de scène door een SKPhysicsBody bijvoorbeeld voor de scène en het toevoegen van een zwaartekracht. Dit betekent dat alle knooppunten in de scène naar beneden worden getrokken.

SKPhysicsBody * physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect: self.frame]; [self.physicsWorld set Gravity: CGVectorMake (0, -9)]; [zelfsetfilosofieBody: fysicabody];

Om de te configureren magneticFieldNode object, moet u zijn fysieke lichaam configureren, evenals zijn positie en sterkte. Merk op dat elk SKFieldNode heeft zijn eigen eigenschappen. Het volgende codefragment laat zien hoe het magneetveldknooppunt moet worden geconfigureerd. We voegen het nieuwe knooppunt toe als een onderliggende knoop aan de scène.

magneticFieldNode = [SKFieldNode magneticField]; [magneticFieldNode setFysicsBody: [SKPhysicsBody bodyWithCircleOfRadius: 80]]; [magneticFieldNode setPosition: CGPointMake (100, 100)]; [magneticFieldNode setStrength: 3]; [self addChild: magneticFieldNode];

Stap 6: Interacties

Om het magnetisch veld in actie te zien, moeten we enkele knooppunten toevoegen waarmee de magnetische veldnoot kan communiceren. In het volgende codefragment maken we driehonderd sprites. Merk op dat elke sprite-node zijn eigen fysica-lichaam heeft en we de affectedByGravity eigendom aan JA.

voor (int i = 0; i < 300; i++)  SKSpriteNode *node4 = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:@"wood.png"] size:CGSizeMake(25, 25)]; [node4 setPhysicsBody:[SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(25, 25)]]; [node4 setPosition:CGPointMake(arc4random()%640, arc4random()%950)]; [node4.physicsBody setDynamic:YES]; [node4.physicsBody setAffectedByGravity:YES]; [node4.physicsBody setAllowsRotation:true]; [node4.physicsBody setMass:0.9]; [self addChild:node4]; 

De voltooide didMoveToView: methode moet er als volgt uitzien:

-(void) didMoveToView: (SKView *) view SKPhysicsBody * physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect: self.frame]; [self.physicsWorld set Gravity: CGVectorMake (0, -9)]; [zelfsetfilosofieBody: fysicabody]; magneticFieldNode = [SKFieldNode magneticField]; [magneticFieldNode setFysicsBody: [SKPhysicsBody bodyWithCircleOfRadius: 80]]; [magneticFieldNode setPosition: CGPointMake (100, 100)]; [magneticFieldNode setStrength: 3]; [self addChild: magneticFieldNode]; voor (int i = 0; i < 300; i++)  SKSpriteNode *node4 = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:@"wood.png"] size:CGSizeMake(25, 25)]; [node4 setPhysicsBody:[SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(25, 25)]]; [node4 setPosition:CGPointMake(arc4random()%640, arc4random()%950)]; [node4.physicsBody setDynamic:YES]; [node4.physicsBody setAffectedByGravity:YES]; [node4.physicsBody setAllowsRotation:true]; [node4.physicsBody setMass:0.9]; [self addChild:node4];  

Voordat we de applicatie bouwen en uitvoeren, overschrijven we de touchesMoved: withEvent: methode, zodat u het magnetisch veld knooppunt kunt verplaatsen door op uw vinger te tikken.

-(ongeldige) aanrakingen Gemeden: (NSSet *) raakt aan met Event: (UIEvent *) event for (UITouch * touch in aanraking) [magneticFieldNode setPosition: [touch locationInNode: self]]; 

Bouw en voer de applicatie uit om het effect van het magnetisch veldknooppunt op de scène te testen. Voor aanvullende informatie over het simuleren van fysica met behulp van het SpriteKit-framework, raad ik aan de documentatie van Apple over dit onderwerp te lezen.

2. SceneKit-integratie

SceneKit is een objectief-C-raamwerk op hoog niveau voor het bouwen van applicaties en games die 3D-afbeeldingen gebruiken. Het ondersteunt de import, manipulatie en weergave van 3D-activa. Het renderalgoritme vereist alleen de beschrijving van de inhoud, animaties en acties van uw scène die u wilt uitvoeren.

Via SceneKit bent u nu in staat om 3D-inhoud te creëren en te leveren met behulp van SpriteKit. SceneKit heeft een boomstructuur en kan op twee manieren worden gebruikt:

  • stand-alone SceneKit-omgeving
  • geïntegreerd in SpriteKit

SceneKit heeft een boomhiërarchiesamenstelling. In een stand-alone SceneKit-omgeving is de basisklasse voor de boomstructuur een SCNNode bijvoorbeeld zoals in het onderstaande schema. Een SCNNode object zelf heeft geen zichtbare inhoud wanneer de scène die het bevat, wordt gerenderd. Het definieert eenvoudig een positie in de ruimte die de positie, rotatie en schaal van een knoop ten opzichte van zijn bovenliggende knooppunt vertegenwoordigt.

t

Wanneer u SceneKit integreert in een op SpriteKit gebaseerde app, moet u een SK3DNode object als het root-object voor uw scène. Dit betekent dat de kern SceneKit-hiërarchie verandert in het volgende:

Merk op dat niet elk kindknooppunt in het bovenstaande diagram vereist is. U definieert en configureert alleen de knooppunten die aan uw behoeften voldoen. U kunt bijvoorbeeld een toevoegen SCNLight knoop om de scène te verlichten, ook als u geen SCNCamera knoop in de scène.

Stap 1: live voorbeeld van modellen

SpriteKit en SceneKit ondersteunen een aantal bestandsindelingen voor het importeren van modellen. U kunt deze modellen in realtime in Xcode bekijken. Binnen in de textures map in uw project(Bronnen> Texturen), er is een bestand met de naam ship.dae. Wanneer u dit bestand selecteert, krijgt u een nieuwe gebruikersinterface te zien, zoals hieronder weergegeven.

Aan de linkerkant van de editor ziet u twee groepen:

  • entiteiten: Deze groep bevat informatie over de vooraf gedefinieerde animaties, camerapositie, licht en materialen die zijn gedefinieerd door het modelbestand. Het bestand dat we hebben geopend bevat alleen informatie over de geometrie van het model en het materiaal.
  • Scène grafiek: Deze groep bevat informatie over het oorspronkelijke objectnetwerk. In dit geval is het object als geheel gemaakt en ziet u slechts één enkele mesh.

Stap 2: Een extern model importeren

Als u SceneKit in combinatie met SpriteKit wilt gebruiken, moet u de SceneKit-bibliotheek importeren vanuit het SceneKit-framework. Open SceneKitScene.m en neem het op zoals hieronder getoond.

#include 

We gaan het model gebruiken dat is opgeslagen in ship.dae als de 3D-scène. Binnen in de didMoveToView: methode, maak het SCNScene object dat een scène uit dat bestand laadt.

SCNScene * shipScene = [SCNScene sceneNamed: @ "ship.dae"];

Denk aan de boomhiërarchie die ik eerder noemde? Om de. Toe te voegen shipScene bezwaar tegen de SKScene object, zijn twee stappen vereist:

  • Maak een SK3DNode voorwerp
  • een SceneKit-scène definiëren om te renderen

In dit geval is de te renderen scène de shipScene. Merk op dat u ook de positie en de grootte van het knooppunt definieert.

SK3DNode * sk3DNodeFist = [[SK3DNode alloc] initWithViewportSize: CGSizeMake (300, 300)]; [sk3DNodeFist setPosition: CGPointMake (200.300)]; [sk3DNodeFist setScnScene: shipScene];

Voeg ten slotte de SK3DNode object als een onderliggende knooppunt voor de SKScene voorwerp.

[self addChild: sk3DNodeFist];

Om het uiteindelijke resultaat een beetje aantrekkelijker te maken, stelt u de achtergrondkleur van de scène in op groen, zoals hieronder wordt weergegeven.

[self setBackgroundColor: [SKColor greenColor]];

Dit is wat de complete didMoveToView: methode zou moeten lijken. Bouw en voer de applicatie uit om het resultaat te zien.

-(void) didMoveToView: (SKView *) weergave [self setBackgroundColor: [SKColor greenColor]]; SCNScene * shipScene = [SCNScene sceneNamed: @ "ship.dae"]; SK3DNode * sk3DNodeFist = [[SK3DNode alloc] initWithViewportSize: CGSizeMake (300, 300)]; [sk3DNodeFist setPosition: CGPointMake (200.300)]; [sk3DNodeFist setScnScene: shipScene]; [self addChild: sk3DNodeFist]; 

Stap 3: Een aangepaste scène maken

Laten we een complexere scène maken die meerdere bevat SCNNode voorwerpen. Voor deze tweede scène moeten we een andere maken SK3DNode voorwerp.

SK3DNode * sk3DNode = [[SK3DNode alloc] initWithViewportSize: CGSizeMake (400, 400)]; [sk3DNode setPosition: CGPointMake (150.200)]; 

Vervolgens maken we de SCNScene object, degene die de knooppunten van het scènekind bevat.

SCNScene * sceneObject = [SCNScene scene];

Deze sceneObject zal drie knooppunten hebben:

  • Camera: Dit knooppunt wordt gebruikt om de scène door een bepaalde positie te bekijken.
  • Licht: Met dit knooppunt kunt u verschillende materiaaleigenschappen van het 3D-object bekijken. U definieert normaal het lichttype en de kleur.
  • 3D-object: Dit is het geïmporteerde of gedefinieerde object in uw code. Met SceneKit kunt u standaard verschillende parametrische 3D-objecten definiëren, dat wil zeggen torus, doos, piramide, bol, cilinder, kegel, buis, capsule, vloer, 3D-tekst of een aangepaste vorm.

Voor elk afzonderlijk knooppunt voert u altijd drie acties uit. Laten we het cameraknooppunt als voorbeeld nemen.

  1. Creëer een SCNCamera object en definieer de eigenschappen ervan.
  2. Creëer een SCNNode waarop het SCNCamera zal worden toegewezen.
  3. Voeg de toe SCNNode als een kindknooppunt voor de SCNScene voorwerp.

Laten we nu de drie knooppunten maken die ik eerder noemde. Dit is wat we moeten implementeren om het cameraknooppunt te maken.

SCNCamera * camera = [SCNCamera camera]; SCNNode * cameraNode = [knooppunt SCNNode]; [cameraNode setCamera: camera]; [cameraNode setPosition: SCNVector3Make (0, 0, 40)]; [sceneObject.rootNode addChildNode: cameraNode];

Standaard bevinden de cameralocatie en 3D-scène zich aan de oorsprong, (0,0,0). Met de eigenschap position kunt u de camera langs de drie x-, y- en z-assen aanpassen om de positie te wijzigen.

Het lichtknooppunt vereist iets meer werk, maar het volgende codefragment moet gemakkelijk te begrijpen zijn.

SCNLight * spotLight = [SCNLight-lampje]; [spotLight setType: SCNLightTypeDirectional]; [spotLight setColor: [SKColor redColor]]; SCNNode * spotLightNode = [knooppunt SCNNode]; [spotLightNode-setLight: spotLight]; [spotLightNode setPosition: SCNVector3Make (0, 0, 5)]; [cameraNode addChildNode: spotLightNode]; [sceneObject.rootNode addChildNode: spotLightNode];

We zullen ook een torus-object maken zoals weergegeven in het volgende codefragment.

SCNTorus * torus = [SCNTorus torusWithRingRadius: 13 pipeRadius: 1.5]; SCNNode * torusNode = [SCNNode-knooppuntWithGeometry: torus]; [torusNode setTransform: SCNMatrix4MakeRotation (M_PI / 3, 0, 1, 0)]; [sceneObject.rootNode addChildNode: torusNode];

Ten slotte stellen we de scène in die we willen weergeven en toevoegen sk3DNode als een kindknooppunt van de SKScene aanleg.

[sk3DNode setScnScene: sceneObject]; [self addChild: sk3DNode];

Dit is wat de finale is didMoveToView: methode zou moeten lijken.

-(void) didMoveToView: (SKView *) weergave [self setBackgroundColor: [SKColor greenColor]]; SCNScene * shipScene = [SCNScene sceneNamed: @ "ship.dae"]; SK3DNode * sk3DNodeFist = [[SK3DNode alloc] initWithViewportSize: CGSizeMake (300, 300)]; [sk3DNodeFist setPosition: CGPointMake (200.300)]; [sk3DNodeFist setScnScene: shipScene]; [self addChild: sk3DNodeFist]; SK3DNode * sk3DNode = [[SK3DNode alloc] initWithViewportSize: CGSizeMake (400, 400)]; [sk3DNode setPosition: CGPointMake (150.200)]; SCNScene * sceneObject = [SCNScene scene]; SCNCamera * camera = [SCNCamera camera]; SCNNode * cameraNode = [knooppunt SCNNode]; [cameraNode setCamera: camera]; [cameraNode setPosition: SCNVector3Make (0, 0, 40)]; [sceneObject.rootNode addChildNode: cameraNode]; SCNLight * spotLight = [SCNLight-lampje]; [spotLight setType: SCNLightTypeDirectional]; [spotLight setColor: [SKColor redColor]]; SCNNode * spotLightNode = [knooppunt SCNNode]; [spotLightNode-setLight: spotLight]; [spotLightNode setPosition: SCNVector3Make (0, 0, 5)]; [cameraNode addChildNode: spotLightNode]; [sceneObject.rootNode addChildNode: spotLightNode]; SCNTorus * torus = [SCNTorus torusWithRingRadius: 13 pipeRadius: 1.5]; SCNNode * torusNode = [SCNNode-knooppuntWithGeometry: torus]; [torusNode setTransform: SCNMatrix4MakeRotation (M_PI / 3, 0, 1, 0)]; [sceneObject.rootNode addChildNode: torusNode]; [sk3DNode setScnScene: sceneObject]; [self addChild: sk3DNode]; 

Bouw en voer de applicatie uit. Je zou iets moeten zien dat lijkt op het volgende screenshot.

Stap 4: De scène animeren

U kunt de scène animeren met behulp van de CABasicAnimation klasse. U hoeft alleen een instantie van te maken CABasicAnimation door aan te roepen animationWithKeyPath:. De animatie die we in het volgende codefragment maken, loopt oneindig door en heeft een duur van vijf seconden. Voeg het volgende codefragment toe aan de didMoveToView: methode.

CABasicAnimation * torusRotation = [CABasicAnimation animationWithKeyPath: @ "rotation"]; torusRotation.byValue = [NSValue-waardeWithSCNVector4: SCNVector4Make (1, 1, 0, 4.0 * M_PI)]; [torusRotation setTimingFunction: [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionLinear]]; [torusRotation setRepeatCount: INFINITY]; [torusRotation setDuration: 5.0]; [torusNode addAnimation: torusRotation forKey: nil];

Bouw en voer de applicatie uit om de animatie te testen.

3. Meer SpriteKit

Als je meer wilt weten over SpriteKit, raad ik je aan de volgende SpriteKit-handleidingen te lezen:

  • Bouw een vliegtuigspel met Sprite Kit 
  • Bouw raketopdracht met Sprite Kit 
  • iOS SDK: bouw een feitengame

Als u meer wilt lezen over het SpriteKit-framework, raad ik u aan de Apple SpriteKit-programmeerhandleiding te lezen of door de referentiekader te bladeren..

Conclusie

Hiermee is de tweede tutorial van deze tweedelige serie over de nieuwe functies van het SpriteKit-framework, geïntroduceerd in iOS 8, afgesloten. In dit deel heb je geleerd hoe je physics-simulatie kunt gebruiken en SceneKit kunt integreren. Als u vragen of opmerkingen heeft, kunt u een opmerking plaatsen in de opmerkingen.