Î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.
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.
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.
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.
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
.
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
.
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
.
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 Dusman, Subclasa 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.
Ș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ă.
Î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ă!
.