SpriteKit de bază Punerea totul împreună

Ce veți crea

În acest post vom construi un joc simplu de la zero. Pe parcurs, vom aborda câteva dintre cele mai importante aspecte ale bibliotecii SpriteKit.

Acest post se bazează pe ceea ce am învățat mai devreme în seria de bază SpriteKit. Dacă doriți să vă reîmprospătați cunoștințele SpriteKit, aruncați o privire la unele dintre celelalte postări ale mele.

Proiect nou

Deschideți Xcode și începeți un nou proiect din meniu Fişier > Nou Proiect. Asigura-te iOS este selectat și alegeți Joc ca șablon.

Dă-ți numele unui proiect și asigură-te Limba este setat sa Rapid, Tehnologia jocurilor este setat sa SpriteKit, și Dispozitive este setat sa iPad.

Planificarea scenelor de joc

Unul dintre primele lucruri pe care îmi place să le fac atunci când creez un proiect este de a determina cât de multe scene voi avea nevoie pentru proiect. De obicei, voi avea cel puțin trei scene: o scenă intro, o scena principală de joc și o scenă pentru a afișa scoruri mari etc.

Pentru acest exemplu, avem nevoie doar de o scenă de intro și de joc, deoarece nu vom urmări viața, scorurile etc. SpriteKit vine deja cu o scenă când creați un nou proiect, așa că avem nevoie de o scenă intro.

Din meniul Xcode, alegeți Fişier > Nou > Fişier. Asigura-te iOS este selectat și alegeți Cocoa Touch Class.

Denumiți clasa StartGameScene, și asigurați-vă că Subclasa de este setat sa SKScene și Limba este setat sa Rapid.

Configurarea GameViewController

Deschis GameViewController.swift. Ștergeți totul din fișierul respectiv și înlocuiți-l cu următoarele.

import Import UIKit Import SpriteKit Clasa GameplayKit GameViewController: UIViewController override func viewDidLoad () super.viewDidLoad () let scenă = StartGameScene (size: view.bounds.size) let skView = self.view as! SKView skView.showsFPS = falsă skView.showsNodeCount = falsă skView.ignoresSiblingOrder = falsă scena.scaleMode = .aspectFill skView.presentScene (scenă) suprascrie var prefersStatusBarHidden: Bool return true 

Când creați un nou proiect, GameViewController.swift este setat să se încarce GameScene.sks de pe disc. GameScene.sks este folosit împreună cu editorul de scenă încorporat al SpriteKit, care vă permite să vă prezentați vizual proiectele. Nu vom folosi GameScene.sks, și va crea în schimb totul de la cod, deci aici inițiază o nouă instanță de StartGameScene și să o prezinte.

Creați scena intro

Adăugați următoarele la noul creat StartGameScene.swift.

importați Importul UIKit Clasa SpriteKit StartGameScene: SKScene override func didMove (pentru a vizualiza: SKView) scena? .backgroundColor = .blue let logo = SKSpriteNode (imageNamed: "bigplane") logo.position = CGPoint (x: size.width / , y: size.height / 2) addChild (logo) lasă newGameBtn = SKSpriteNode (imageNamed: "newgamebutton") newGameBtn.position = CGPoint (x: size.width / 2, y: size.height / 2 - 350) newGameBtn. nume = "newgame" addChild (newGameBtn) suprascrie func atingeBegan (_ atinge: Set, cu evenimentul: UIEvent?) paza permite atingere = atinge intai altceva retur lasa touchLocation = touch.location (in: sine) let touchedNode = self.atPoint (touchLocation) permiteți newScene = GameScene (dimensiune: dimensiune) newScene.scaleMode = vizualizare scaleMode? .presentScene (newScene) 

Această scenă este destul de simplă. În didMove , adăugăm un logo și un buton. Apoi în touchesBegan, detectăm atingerile noului buton de joc și răspund prin încărcarea scenei principale GameScene.

Planificarea jocurilor

Următorul lucru pe care îmi place să-l fac atunci când creez un nou joc este să decid ce clase am nevoie. Pot spune imediat că voi avea nevoie de a Jucător clasă și an Dusman clasă. Ambele clase se vor extinde SKSpriteNode. Cred că pentru acest proiect vom crea doar gloanțe jucător și inamic chiar din cadrul claselor lor respective. Ai putea face bullet de jucator separat și clase de bullet inamic dacă preferi și îți sugerez să încerci să faci asta ca pe un exercițiu pe cont propriu. 

În cele din urmă, există insulele. Acestea nu au nicio funcționalitate specifică, ci se deplasează în jos pe ecran. În acest caz, deoarece sunt doar decorațiuni, cred că este, de asemenea, bine să nu creați o clasă, ci să le creați în principiu GameScene.

Crearea Jucător Clasă

Din meniul Xcode, alegeți Fişier > Nou > Fişier.  Asigura-te iOS este selectat și alegeți Cocoa Touch Class.

Asigura-te ca Clasă este setat sa Jucător, Subclasa de: este setat sa SKSpriteNode, și Limba este setat sa Rapid.

Acum adăugați următoarele Player.swift.

Importul UIKit import SpriteKit class Player: SKSpriteNode private var canFire = adevărat privat var invincibil = false privat var var: Int = 3 didSet if < 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]))  

În cadrul init () metoda, am creat physicsBody și invoca generateBullets (). generateBullets metoda invocă în mod repetat fireBullet (), care creează un glonț, își stabilește physicsBody, și o mută pe ecran.

Când jucătorul își pierde viața, respawn () metoda este invocată. În cadrul respawn metodă, se estompează avionul din și de cinci ori, timp în care jucătorul va fi invincibil. Un jucător a epuizat toate viețile, ucide() metoda este invocată. Metoda de ucidere pur și simplu încarcă StartGameScene.

Crearea clasei de inamici

Alege Fişier > Nou > Fişier din meniul Xcode. Asigura-te iOS este selectat și alegeți Cocoa Touch Class.

Asigura-te ca Clasă este setat sa DusmanSubclasa de: este setat sa SKSpriteNode, și Limba este setat sa Rapid.

Adăugați următoarele la Enemy.swift.

importare Import UIKit Clasă SpriteKit Enemy: SKSpriteNode init () permite textura = SKTexture (imageNamed: "enemy1") super.init (textură: textură, culoare: .clear, inamic "auto.physicsBody = SKPhysicsBody (textură: self.texture!, dimensiune: self.size) self.physicsBody? .isDynamic = adevărat self.physicsBody? .categoryBitMask = PhysicsCategories.Enemy self.physicsBody? .contactTestBitMask = PhysicsCategories.Player | ())  () () () () () () bullet.position.x = auto.position.x bullet.position.y = auto.position.y - bullet.size.height * 2 bullet.physicsBody = SKPhysicsBody (rectangleOf: bullet.size) bullet.physicsBody ?. (pentru: CGPoint (x: self.position.x, y: 0 - bullet.size.height), pentru a vă permite să faceți clic pe butonul de căutare. ()) func move () let moveEnemyAction = SKAction.moveTo (y: 0 - self.size.height, durată: 12.0) lasă removeEnemyAction = SKAction.removeFromParent () lasă moveEnemySequence = SKAction.sequence ([moveEnemyAction, removeEnemyAction]) execută (moveEn ()) func generateBullets () let fireBulletAction = SKAction.run [self self] în sine? .fireBullet () let waitToFire = SKAction.wait (forDuration: 1.5) let fireBulletSequence = SKAction.sequence ([fireBulletAction, waitToFire] ) lasa foc = SKAction.repeatForever (fireBulletSequence) rula (foc)

Această clasă este destul de similar cu Jucător clasă. Am stabilit-o physicsBody și invoca generateBullets (). mișcare() pur și simplu mișcă inamicul pe ecran.

Crearea Scenei principale a jocului

Șterge totul înăuntru GameScene.swift și adăugați următoarele.

import import SpriteKit GameplayKit import Clasa CoreMotion GameScene: SKScene, SKPhysicsContactDelegate permite jucatorului = Player () sa lase motionManager = CMMotionManager () var accelerationX: CGFloat = 0.0 override func didMove (pentru vizualizare: SKView) physicsWorld.gravity = CGVector , dy: 0.0) self.physicsWorld.contactDelegate = auto-scena? .backgroundColor = .blue physicsBody = SKPhysicsBody (edgeLoopFrom: frame) fizicaBody? .categoryBitMask = PhysicsCategories.EdgeBody player.position = CGPoint (x: size.width / : player.size.height) addChild (player) setupAccelerometer () addEnemies () generateIslands () override func atingeBegan (_ atinge: Set, cu evenimentul: UIEvent?)  func addEnemies () let generateEnemyAction = SKAction.run [self self] în sine? .generateEnemy () waitToGenerateEnemy = SKAction.wait (forDuration: 3.0) let generateEnemySequence = [generateEnemyAction, waitToGenerateEnemy]) run (SKAction.repeatForever (generateEnemySequence)) func generateEnemy () enemy = enemy.position = CGPoint (x: CGFloat (arc4random_uniform (UInt32 )) func_Begin (_ 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)   

Creăm un exemplu de Jucător și un exemplu de CMMotionManager. Folosim accelerometrul pentru a muta jucatorul in acest joc.

În cadrul didMove (la :) metodă vom opri gravitatea, înființat contactDelegate, adăugați o buclă de margine și setați jucătorînaintea adăugării la scenă. Apoi, invocăm setupAccelerometer (), care stabilește accelerometrul și invocă addEnemies () și generateIslands () metode.

addEnemies () metoda invocă în mod repetat generateEnemy () metoda, care va crea un exemplu de Dusman și adăugați-o la scenă.

generateIslands () metoda funcționează similar cu addEnemies () metodă prin faptul că solicită în mod repetat createIsland () care creează un SKSpriteNode și o adaugă la scenă. În createIsland (), de asemenea, creăm un SKAction care mișcă insula în scenă.

În cadrul didBegin (_ :) , verificăm pentru a vedea care noduri fac contact și răspund prin eliminarea nodului corespunzător din scenă și a invocării player.die () daca este necesar. createExplosion () metoda creează o animație de explozie și o adaugă la scenă. Odată ce explozia este terminată, este scoasă din scenă.

Concluzie

În această serie, am învățat câteva dintre cele mai importante concepte folosite în aproape toate jocurile SpriteKit. Am terminat seria, arătând cât de simplu este să obțineți și să rulați un joc de bază. Există încă unele îmbunătățiri care ar putea fi făcute, cum ar fi un HUB, scoruri mari și sunete (am inclus și câteva MP3-uri pe care le puteți folosi pentru acest lucru în repo). Sper că ați învățat ceva util în întreaga serie și vă mulțumim pentru lectură!

.

Cod