In diesem Beitrag erstellen wir ein einfaches Spiel von Grund auf. Dabei werden wir auf einige der wichtigsten Aspekte der SpriteKit-Bibliothek eingehen.
Dieser Beitrag baut auf dem auf, was wir zuvor in der SpriteKit Basics-Serie gelernt haben. Wenn Sie Ihr SpriteKit-Wissen aktualisieren möchten, werfen Sie einen Blick auf einige meiner anderen Beiträge.
Öffnen Sie Xcode und starten Sie ein neues Projekt aus dem Menü Datei > Neu > Projekt. Stelle sicher iOS ist ausgewählt und wählen Sie Spiel als Vorlage.
Geben Sie Ihrem Projekt einen Namen und stellen Sie sicher, dass dies der Fall ist Sprache ist eingestellt auf Schnell, Spieltechnologie ist eingestellt auf SpriteKit, und Geräte ist eingestellt auf iPad.
Eines der ersten Dinge, die ich beim Erstellen eines Projekts am liebsten machen möchte, ist zu bestimmen, wie viele Szenen ich für das Projekt benötige. Ich werde in der Regel mindestens drei Szenen haben: eine Intro-Szene, eine Hauptspielszene und eine Szene, die Highscores usw. zeigt.
Für dieses Beispiel benötigen wir lediglich ein Intro und eine Hauptspielszene, da wir nicht über das Leben, die Ergebnisse usw. nachverfolgen können. SpriteKit enthält bereits eine Szene, wenn Sie ein neues Projekt erstellen. Daher benötigen wir nur eine Intro-Szene.
Wählen Sie im Xcode-Menü Datei > Neu > Datei. Stelle sicher iOS ausgewählt ist und wählen Sie Kakao-Touch-Klasse.
Benennen Sie die Klasse StartGameScene, und stellen Sie sicher, dass Unterklasse von ist eingestellt auf SKScene und Sprache ist eingestellt auf Schnell.
Öffnen GameViewController.swift. Löschen Sie alles in dieser Datei und ersetzen Sie es durch das Folgende.
import UIKit importieren SpriteKit importieren GameplayKit-Klasse GameViewController: UIViewController überschreiben func viewDidLoad () super.viewDidLoad () let scene = StartGameScene (Größe: view.bounds.size) let skView = self.view as! SKView skView.showsFPS = false skView.showsNodeCount = false skView.ignoresSiblingOrder = false scene.scaleMode = .aspectFill skView.presentScene (scene) Überschreibt var prefersStatusBarHidden: Bool return true
Wenn Sie ein neues Projekt erstellen, GameViewController.swift ist zum Laden eingerichtet GameScene.sks von der Festplatte. GameScene.sks wird zusammen mit dem in SpriteKit integrierten Szenen-Editor verwendet, mit dem Sie Ihre Projekte visuell anordnen können. Wir werden nicht verwenden GameScene.sks, Stattdessen wird alles aus Code erstellt. Daher initiieren wir hier eine neue Instanz von StartGameScene und präsentiere es.
Fügen Sie dem neu erstellten Folgendes hinzu StartGameScene.swift.
import UIKit import SpriteKit-Klasse StartGameScene: SKScene override func didMove (zum Anzeigen von SKView) szene.backgroundColor = .blue let logo = SKSpriteNode (imageNamed: "bigplane") logo.position = CGPoint (x: size.width / 2) , y: size.height / 2) addChild (logo) let newGameBtn = SKSpriteNode (imageNamed: "newgamebutton") newGameBtn.position = CGPoint (x: size.width / 2, y: size.height / 2 - 350) newGameBtn. name = "newgame" addChild (newGameBtn) überschreibt die Funktion "Berührungen" (_ berührt: "Festlegen"), with event: UIEvent?) guard let touch = touches.first else return let touchLocation = touch.location (in: self) let touchedNode = self.atPoint (touchLocation) if (touchedNode.name == "newgame") let newScene = GameScene (Größe: Größe) newScene.scaleMode = scaleMode-Ansicht? .presentScene (newScene)
Diese Szene ist ziemlich einfach. In dem didMove
Methode fügen wir ein Logo und eine Schaltfläche hinzu. Dann in berührtBegan
, Wir erkennen Berührungen der neuen Spielschaltfläche und reagieren, indem wir die Hauptszene laden GameScene
.
Als nächstes möchte ich bei der Erstellung eines neuen Spiels entscheiden, welche Klassen ich brauche. Ich kann sofort sagen, dass ich eine brauchen werde Spieler
Klasse und ein Feind
Klasse. Beide Klassen werden erweitert SKSpriteNode
. Ich denke, für dieses Projekt werden wir einfach die Spieler- und Feindkugeln direkt aus ihren jeweiligen Klassen erstellen. Wenn Sie möchten, können Sie separate Aufzählungsklassen für Spieler und gegnerische Kugeln erstellen. Ich empfehle Ihnen, dies als Übung alleine zu tun.
Schließlich gibt es noch die Inseln. Diese haben keine spezielle Funktionalität, sondern bewegen sich auf dem Bildschirm nach unten. In diesem Fall denke ich, da es sich nur um Dekorationen handelt, ist es auch in Ordnung, keine Klasse zu erstellen, sondern nur die Hauptkategorie GameScene
.
Spieler
KlasseWählen Sie im Xcode-Menü Datei > Neu > Datei. Stelle sicher iOS ist ausgewählt und wählen Sie Kakao-Touch-Klasse.
Stelle sicher das Klasse ist eingestellt auf Spieler, Unterklasse von: ist eingestellt auf SKSpriteNode, und Sprache ist eingestellt auf Schnell.
Fügen Sie nun folgendes hinzu Spielerwechsel.
import UIKit import SpriteKit-Klasse Player: SKSpriteNode private var canFire = true private var invincible = false private var lebt: Int = 3 didSet if (lebt < 0) kill() else respawn() init() let texture = SKTexture(imageNamed: "player") super.init(texture: texture, color: .clear, size: texture.size()) self.physicsBody = SKPhysicsBody(texture: self.texture!,size:self.size) self.physicsBody?.isDynamic = true self.physicsBody?.categoryBitMask = PhysicsCategories.Player self.physicsBody?.contactTestBitMask = PhysicsCategories.Enemy | PhysicsCategories.EnemyBullet self.physicsBody?.collisionBitMask = PhysicsCategories.EdgeBody self.physicsBody?.allowsRotation = false generateBullets() required init?(coder aDecoder: NSCoder) super.init(coder: aDecoder) func die () if(invincible == false) lives -= 1 func kill() let newScene = StartGameScene(size: self.scene!.size) newScene.scaleMode = self.scene!.scaleMode let doorsClose = SKTransition.doorsCloseVertical(withDuration: 2.0) self.scene!.view?.presentScene(newScene, transition: doorsClose) func respawn() invincible = true let fadeOutAction = SKAction.fadeOut(withDuration: 0.4) let fadeInAction = SKAction.fadeIn(withDuration: 0.4) let fadeOutIn = SKAction.sequence([fadeOutAction,fadeInAction]) let fadeOutInAction = SKAction.repeat(fadeOutIn, count: 5) let setInvicibleFalse = SKAction.run self.invincible = false run(SKAction.sequence([fadeOutInAction,setInvicibleFalse])) func generateBullets() let fireBulletAction = SKAction.run [weak self] in self?.fireBullet() let waitToFire = SKAction.wait(forDuration: 0.8) let fireBulletSequence = SKAction.sequence([fireBulletAction,waitToFire]) let fire = SKAction.repeatForever(fireBulletSequence) run(fire) func fireBullet() let bullet = SKSpriteNode(imageNamed: "bullet") bullet.position.x = self.position.x bullet.position.y = self.position.y + self.size.height/2 bullet.physicsBody = SKPhysicsBody(rectangleOf: bullet.size) bullet.physicsBody?.categoryBitMask = PhysicsCategories.PlayerBullet bullet.physicsBody?.allowsRotation = false scene?.addChild(bullet) let moveBulletAction = SKAction.move(to: CGPoint(x:self.position.x,y:(scene?.size.height)! + bullet.size.height), duration: 1.0) let removeBulletAction = SKAction.removeFromParent() bullet.run(SKAction.sequence([moveBulletAction,removeBulletAction]))
Innerhalb des drin()
Methode einrichten wir die PhysikKörper
und aufrufen generateBullets ()
. Das GenerateBullets
Methode wiederholt Aufrufe fireBullet ()
, das schafft eine Kugel, setzt seine PhysikKörper
, und bewegt sich auf dem Bildschirm nach unten.
Wenn der Spieler ein Leben verliert, wird der Respawn ()
Methode wird aufgerufen. Innerhalb des Respawn
Auf diese Weise blenden wir das Flugzeug fünfmal ein und aus. In dieser Zeit ist der Spieler unbesiegbar. Eines hat der Spieler alle Leben erschöpft, das töten()
Methode wird aufgerufen. Die Kill-Methode lädt einfach die StartGameScene
.
Wählen Datei > Neu > Datei aus dem Xcode-Menü. Stelle sicher iOS ist ausgewählt und wählen Sie Kakao-Touch-Klasse.
Stelle sicher das Klasse ist eingestellt auf Feind, Unterklasse von: ist eingestellt auf SKSpriteNode, und Sprache ist eingestellt auf Schnell.
Fügen Sie Folgendes zu hinzu Feind.
import UIKit import SpriteKit-Klasse Feind: SKSpriteNode init () let texture = SKTexture (imageNamed: "enemy1") super.init (Textur: Textur, Farbe: .klar, Größe: Textur.size ()) self.name = " enemy "self.physicsBody = SKPhysicsBody (Textur: self.texture !, Größe: self.size) self.physicsBody? .isDynamic = true self.physicsBody? .categoryBitMask = PhysicsCategories.Enemy self.physicsBody? .contactTestBitMask = PhysicsCategories.PlayerBullet self.physicsBody? .AllowsRotation = false move () generateBullets () erforderliches init? (Coder aDecoder: NSCoder) super.init (coder: aDecoder) func fireBullet () let bullet = SKSpriteNode (imageNamed: " bullet ") bullet.position.x = self.position.x bullet.position.y = self.position.y - bullet.size.height * 2 bullet.physicsBody = SKPhysicsBody (rechteckleOf: bullet.size) bullet.physicsBody ?. categoryBitMask = PhysicsCategories.EnemyBullet bullet.physicsBody? .allowsRotation = falsche Szene? .addChild (bullet) let moveBulletAction = SKAction.move (zu: CGPoint (x: self.position.x, y: 0 - bullet.size.height), duration: 2.0) let removeBulletAction = SKAction.removeFromParent () bullet.run (SKAction.sequence ([moveBulletAction, removeBulletAction])) func move () letEnemyAction = SKAction.moveTo (y: 0 - self.size.height, duration: 12.0) let removeEnemyAction = SKAction.removeFromParent () let moveEnemySequence = SKAction.sequence ([moveEnemyAction, removeEnemyAction]) ausführen (moveEn.) emySequence) func generateBullets () let fireBulletAction = SKAction.run [schwaches Selbst] in sich selbst? .fireBullet () let waitToFire = SKAction.wait (forDuration: 1.5) ) let fire = SKAction.repeatForever (fireBulletSequence) run (fire)
Diese Klasse ähnelt der Spieler
Klasse. Wir setzen es PhysikKörper
und aufrufen generateBullets ()
. Das Bewegung()
bewegt den Feind einfach den Bildschirm hinunter.
Alles löschen GameScene.swift und fügen Sie folgendes hinzu.
import SpriteKit importieren GameplayKit importieren CoreMotion-Klasse GameScene: SKScene, SKPhysicsContactDelegate let player = Player () let motionManager = CMMotionManager () var accelerateX: CGFloat = 0.0 überschreibt func didMove (zur Ansicht: SKView) physicsWorld.gravity (x) , dy: 0.0) self.physicsWorld.contactDelegate = Selbstszene? .backgroundColor = .blue physicsBody = SKPhysicsBody (edgeLoopFrom: frame) physicsBody? .categoryBitMask = PhysicsCategories.EdgeBody player.position = CGPoint (x: size.width / 2, y : player.size.height) addChild (player) setupAccelerometer () addEnemies () generateIslands () überschreibt die Funktionen von Bears (_ berührt: Set), with event: UIEvent?) func addEnemies () letEnemyAction = SKAction.run [schwaches Selbst] in sich selbst? .generateEnemy () let waitToGenerateEnemy = SKAction.wait (forDuration: 3.0) let generateEnemySequence = SKAction. [generateEnemyAction, waitToGenerateEnemy]) run (SKAction.repeatForever (generateEnemySequence)) func generateEnemy () lass Feind = Feind () addChild (Feind) Feind.position = CGPoint (x: CGFloat (arc4random_uniform) .size.width))) y: size.height - enemy.size.height) func didBegin (_ contact: SKPhysicsContact) var firstBody: SKPhysicsBody var secondBody: SKPhysicsBody if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) firstBody = contact.bodyA secondBody = contact.bodyB else firstBody = contact.bodyB secondBody = contact.bodyA if((firstBody.categoryBitMask & PhysicsCategories.Player != 0) && (secondBody.categoryBitMask & PhysicsCategories.Enemy != 0)) player.die() secondBody.node?.removeFromParent() createExplosion(position: player.position) if((firstBody.categoryBitMask & PhysicsCategories.Player != 0) && (secondBody.categoryBitMask & PhysicsCategories.EnemyBullet != 0)) player.die() secondBody.node?.removeFromParent() if((firstBody.categoryBitMask & PhysicsCategories.Enemy != 0) && (secondBody.categoryBitMask & PhysicsCategories.PlayerBullet != 0)) if(firstBody.node != nil) createExplosion(position: (firstBody.node?.position)!) firstBody.node?.removeFromParent() secondBody.node?.removeFromParent() func createExplosion(position: CGPoint) let explosion = SKSpriteNode(imageNamed: "explosion1") explosion.position = position addChild(explosion) var explosionTextures:[SKTexture] = [] for i in 1… 6 explosionTextures.append(SKTexture(imageNamed: "explosion\(i)")) let explosionAnimation = SKAction.animate(with: explosionTextures, timePerFrame: 0.3) explosion.run(SKAction.sequence([explosionAnimation, SKAction.removeFromParent()])) func createIsland() let island = SKSpriteNode(imageNamed: "island1") island.position = CGPoint(x: CGFloat(arc4random_uniform(UInt32(size.width - island.size.width))), y: size.height - island.size.height - 50) island.zPosition = -1 addChild(island) let moveAction = SKAction.moveTo(y: 0 - island.size.height, duration: 15) island.run(SKAction.sequence([moveAction, SKAction.removeFromParent()])) func generateIslands() let generateIslandAction = SKAction.run [weak self] in self?.createIsland() let waitToGenerateIslandAction = SKAction.wait(forDuration: 9) run(SKAction.repeatForever(SKAction.sequence([generateIslandAction, waitToGenerateIslandAction]))) func setupAccelerometer() motionManager.accelerometerUpdateInterval = 0.2 motionManager.startAccelerometerUpdates(to: OperationQueue(), withHandler: accelerometerData, error in guard let accelerometerData = accelerometerData else return let acceleration = accelerometerData.acceleration self.accelerationX = CGFloat(acceleration.x) ) override func didSimulatePhysics() player.physicsBody?.velocity = CGVector(dx: accelerationX * 600, dy: 0)
Wir erstellen eine Instanz von Spieler
und ein Beispiel von CMMotionManager
. Wir verwenden den Beschleunigungssensor, um den Spieler in diesem Spiel zu bewegen.
Innerhalb des didMove (bis :)
Methode schalten wir die Schwerkraft aus, richten die ein contactDelegate
, fügen Sie eine Kantenschleife hinzu, und legen Sie das fest Spieler
Position vor dem Hinzufügen zur Szene. Wir rufen dann an SetupAccelerometer ()
, der den Beschleunigungsmesser aufstellt und den addEnemies ()
und generateIslands ()
Methoden.
Das addEnemies ()
Methode ruft wiederholt die generateEnemy ()
Methode, die eine Instanz von Feind
und füge es der Szene hinzu.
Das generateIslands ()
Methode funktioniert ähnlich wie die addEnemies ()
Methode, dass es wiederholt aufruft createIsland ()
was schafft ein SKSpriteNode
und fügt es der Szene hinzu. Innerhalb createIsland ()
, wir schaffen auch eine SKAction
das bewegt die Insel die Szene hinunter.
Innerhalb des didBegin (_ :)
Auf diese Weise prüfen wir, welche Knoten Kontakt aufnehmen und reagieren, indem wir den entsprechenden Knoten aus der Szene entfernen und aufrufen player.die ()
wenn erforderlich. Das createExplosion ()
Die Methode erstellt eine Explosionsanimation und fügt sie der Szene hinzu. Sobald die Explosion beendet ist, wird sie aus der Szene entfernt.
In dieser Serie haben wir einige der wichtigsten Konzepte kennen gelernt, die in fast allen SpriteKit-Spielen verwendet werden. Wir beendeten die Serie, indem wir zeigten, wie einfach es ist, ein grundlegendes Spiel zum Laufen zu bringen. Es gibt noch einige Verbesserungen, die vorgenommen werden könnten, wie ein HUB, Highscores und Sounds (ich habe ein paar MP3s mit einbezogen, die Sie im Repo verwenden können). Ich hoffe, dass Sie in dieser Serie etwas Nützliches gelernt haben und vielen Dank für das Lesen!
.