SpriteKit en SceneKit zijn iOS-frameworks die ontworpen zijn om het ontwikkelaars gemakkelijk te maken om 2D- en 3D-items te maken in casual games. In deze zelfstudie laat ik je zien hoe je inhoud die in beide kaders is gemaakt, kunt combineren tot één weergave om de API's te gebruiken die Apple beschikbaar heeft gesteld.
Je zult dit bereiken door een eenvoudige afspeel- / pauzeknop en scoreverzorgingsfunctionaliteit toe te voegen aan een 3D SceneKit-scène door het gebruik van een 2D SpriteKit-gebaseerde interface.
Deze tutorial vereist dat je minimaal Xcode 6+ gebruikt en eerdere ervaring hebt met de basisinhoud van SpriteKit en SceneKit. Als dat niet het geval is, raad ik je aan om eerst enkele van onze andere Tuts + tutorials over SpriteKit en SceneKit te lezen.
Het wordt ook aanbevolen om een fysiek iOS-apparaat te gebruiken om te testen, waarvoor een actief, betaald iOS-ontwikkelaarsaccount vereist is. Je zult ook het startersproject van GitHub moeten downloaden.
Wanneer u het startersproject opent, ziet u dat, naast de standaardinstelling AppDelegate
en ViewController
klassen, je hebt ook twee andere klassen, MainScene
en OverlayScene
.
De MainScene
class is een subklasse van SCNScene
en biedt de 3D-inhoud van uw app. Evenzo, de OverlayScene
class is een subklasse van SKScene
en bevat de 2D SpriteKit-inhoud in uw app.
Kijk gerust naar de implementaties van deze lessen. Het moet er bekend uitzien als je wat ervaring hebt met SpriteKit en SceneKit. In uw ViewController
klasse viewDidLoad
methode, vindt u ook de code voor het instellen van een basis SCNView
aanleg.
Bouw en voer uw app uit op de iOS Simulator of op uw fysieke apparaat. In dit stadium bevat uw app een blauwe roterende kubus.
Het is tijd om een SpriteKit-scène bovenop de 3D-inhoud toe te voegen. Dit wordt gedaan door het instellen van overlaySKScene
eigendom van elk object dat voldoet aan de SCNSceneRenderer
protocol, in ons voorbeeld is dat het SCNView
aanleg. In ViewController.swift voeg de volgende regels toe aan de viewDidLoad
methode:
override func viewDidLoad () ... self.spriteScene = OverlayScene (size: self.view.bounds.size) self.sceneView.overlaySKScene = self.spriteScene
Wanneer u uw app opnieuw opbouwt en uitvoert, ziet u dat u nu een pauzeknop linksonder heeft geplaatst en een scoretiket midden in het beeld van uw app..
U vraagt zich misschien af waarom het beter is om deze eigenschap te gebruiken in plaats van gewoon een SKView
als een subweergave van de SCNView
voorwerp. Wanneer de overlaySKScene
eigenschap wordt gebruikt, zowel de 2D- als de 3D-componenten van uw app gebruiken dezelfde OpenGL-context om inhoud op het scherm weer te geven. Dit presteert aanzienlijk beter dan het maken van twee afzonderlijke weergaven, die elk hun eigen OpenGL-context en renderingpijplijn hebben. Hoewel het verschil te verwaarlozen is voor deze eenvoudige installatie, kunnen de prestaties die in pils worden bereikt, complexere scènes van onschatbare waarde zijn.
Er zijn veel verschillende manieren waarop u informatie tussen uw kunt overbrengen MainScene
en OverlayScene
instances. In deze tutorial ga je key-value observing gebruiken, KVO afgekort.
Voordat u de mogelijkheid om de kubusanimatie te onderbreken implementeert, moet u deze functionaliteit eerst toevoegen aan de SpriteKit-scène. In OverlayScene.swift, voeg de volgende methode toe aan de OverlayScene
klasse:
override func touchesEnded (raakt aan: Set, withEvent event: UIEvent) let touch = touches.first as? UITouch let location = touch? .LocationInNode (self) if self.pauseNode.containsPoint (location!) If! Self.paused self.pauseNode.texture = SKTexture (imageNamed: "Play Button") else self.pauseNode. texture = SKTexture (imageNamed: "Pause Button") self.paused =! self.paused
De touchesEnded (_: withEvent :)
methode wordt aangeroepen wanneer de gebruiker zijn vinger (s) van het scherm van het apparaat haalt. In deze methode controleert u of de gebruiker de pauzeknop heeft aangeraakt en de scène dienovereenkomstig heeft bijgewerkt. Bouw en voer je app opnieuw uit om te controleren of dit stukje van de puzzel correct werkt.
We moeten nu stoppen met roteren van de 3D-kubus wanneer de pauze-knop is aangeraakt door de gebruiker. Ga terug naar ViewController.swift en voeg de volgende regel toe aan de viewDidLoad
methode:
override func viewDidLoad () ... self.spriteScene.addObserver (self.sceneView.scene !, forKeyPath: "paused", options: .New, context: nil)
Voeg ten slotte de volgende methode toe aan MainScene.swift om observatie van sleutel / waarde in te schakelen:
override func observeValueForKeyPath (keyPath: String, ofObject-object: AnyObject, wijzigen: [NSObject: AnyObject], context: UnsafeMutablePointer) als keyPath == "onderbroken" self.paused = wijzig [NSKeyValueChangeNewKey] als! Bool
Als u uw app opnieuw bouwt en uitvoert, moet de kubus stoppen met draaien wanneer op de pauzeknop wordt getikt.
Net zoals informatie kan worden overgedragen van een SpriteKit-scène naar een SceneKit-scène, kunt u ook gegevens van SceneKit-instanties naar SpriteKit-instanties verzenden. In deze eenvoudige app, ga je een punt toevoegen aan de score elke keer dat de kubus door de gebruiker wordt aangeraakt. In ViewController.swift, voeg de volgende methode toe:
override func touchesEnded (raakt aan: Set, withEvent event: UIEvent) let touch = touches.first as? UITouch let location = touch? .LocationInView (self.sceneView) laat hitResults = self.sceneView.hitTest (location !, options: nil) voor resultaat in (hitResults as! [SCNHitTestResult]) if result.node == (self. sceneView.scene as! MainScene) .cubeNode self.spriteScene.score + = 1
Merk op dat we de touchesEnded (_: withEvent :)
methode in plaats van een UITapGestureRecognizer
, omdat UIGestureRecognizer
objecten veroorzaken de touchesEnded (_: withEvent :)
methode die zeer inconsistent moet worden uitgevoerd. Omdat u deze methode gebruikt voor de pauzeknop, moet u er zeker van zijn dat deze elke keer dat de gebruiker op het scherm tikt, wordt aangeroepen.
In de touchesEnded (_: withEvent :)
methode, we voeren een druktest uit voor de uiteindelijke locatie van een aanraking in uw sceneView
. Als de locatie van de aanraking overeenkomt met de locatie van de kubus, wordt één punt toegevoegd aan de score van uw spriteScene
. De tekst in de scène wordt automatisch bijgewerkt dankzij de waarnemer van de eigenschap partituur
eigendom in de OverlayScene
klasse.
Voer uw app opnieuw uit en tik op de kubus om te controleren of het scoretiket wordt bijgewerkt wanneer op de kubus wordt getikt.
Zowel de pauzeknop als het scoretiket zijn voorbeelden van hoe u informatie tussen SpriteKit- en SceneKit-scènes kunt overbrengen. Deze informatie is echter niet beperkt tot numerieke en booleaanse waarden, het kan elk gegevenstype zijn dat uw project nodig heeft.
Behalve dat je een SpriteKit-scène bovenop een SceneKit-scène kunt leggen, kun je ook een SKScene
bijvoorbeeld als een materiaal voor SceneKit-geometrie. Dit wordt gedaan door een SKScene
bezwaar tegen de inhoud
eigendom van een SCNMaterialProperty
voorwerp. Hiermee kunt u eenvoudig een geanimeerd materiaal toevoegen aan elk 3D-object.
Laten we een voorbeeld bekijken. In je app ga je een eenvoudige kleurovergang-animatie toevoegen aan de kubus in plaats van het statische blauw dat het momenteel heeft. In de in het
methode van de MainScene
klasse, vervang het volgende codeblok:
override init () super.init () let cube = SCNBox (width: 3, height: 3, length: 3, chamferRadius: 0) let cubeMaterial = SCNMaterial () cubeMaterial.diffuse.contents = UIColor.blueColor () cube. materials = [cubeMaterial] self.cubeNode = SCNNode (geometry: cube) self.cubeNode.runAction (SCNAction.repeatActionForever (SCNAction.rotateByX (0, y: 0.01, z: 0, duration: 1.0 / 60.0))) ...
met dit codeblok:
override init () super.init () let cube = SCNBox (breedte: 3, height: 3, length: 3, chamferRadius: 0) let materialScene = SKScene (maat: CGSize (width: 100, height: 100)) let backgroundNode = SKSpriteNode (kleur: UIColor.blueColor (), size: materialScene.size) backgroundNode.position = CGPoint (x: materialScene.size.width / 2.0, y: materialScene.size.height / 2.0) materialScene.addChild (backgroundNode) laat blueAction = SKAction.colorizeWithColor (UIColor.blueColor (), colorBlendFactor: 1, duration: 1) laat redAction = SKAction.colorizeWithColor (UIColor.redColor (), colorBlendFactor: 1, duration: 1) let greenAction = SKAction.colorizeWithColor (UIColor .greenColor (), colorBlendFactor: 1, duration: 1) backgroundNode.runAction (SKAction.repeatActionForever (SKAction.sequence ([blueAction, redAction, greenAction]))) laat cubeMaterial = SCNMaterial () cubeMaterial.diffuse.contents = materialScene cube. materials = [cubeMaterial] self.cubeNode = SCNNode (geometry: cube) self.cubeNode.runAction (SCNAction.repeatAction Voor altijd (SCNAction.rotateByX (0, y: 0.01, z: 0, duration: 1.0 / 60.0))) ...
Dit codefragment maakt een eenvoudig SKScene
bijvoorbeeld met één achtergrondknooppunt, dat aanvankelijk blauw is. Vervolgens maken we drie acties voor de overgang van blauw naar rood en groen. We voeren de acties in een herhalende reeks op het achtergrondknooppunt uit.
Hoewel we in ons voorbeeld basiskleuren hebben gebruikt, kan alles wat in een SpriteKit-scène kan worden gedaan, worden omgezet in een SceneKit-materiaal.
Bouw en voer uw app nog één keer uit. Je zult zien dat de kleur van de kubus overgaat van blauw naar rood en groen.
Merk op dat het onderbreken van de SceneKit-scène de SpriteKit-scène die we als materiaal hebben gebruikt niet onderbreekt. Om de animatie van het materiaal te pauzeren, moet je een verwijzing naar de SpriteKit-scène bijhouden en deze expliciet pauzeren.
Het combineren van de inhoud van SpriteKit en SceneKit kan op verschillende manieren zeer nuttig zijn. Als u een 2D-scène bovenop een 3D-scène plaatst, kunt u een dynamische interface maken en dit zal resulteren in een prestatiewinst omdat beide scènes dezelfde OpenGL-context en renderingpijplijn gebruiken. Je hebt ook geleerd hoe je SpriteKit kunt gebruiken om geanimeerde materialen voor 3D-objecten te maken. Als je opmerkingen of vragen hebt, laat ze dan achter in de reacties hieronder.