Principes de base de SpriteKit tout rassembler

Ce que vous allez créer

Dans cet article, nous allons construire un jeu simple à partir de zéro. En cours de route, nous aborderons certains des aspects les plus importants de la bibliothèque SpriteKit..

Cet article s'appuie sur ce que nous avons appris précédemment dans la série Bases de SpriteKit. Si vous souhaitez actualiser vos connaissances sur SpriteKit, jetez un œil à certains de mes autres articles..

Nouveau projet

Ouvrez Xcode et démarrez un nouveau projet à partir du menu. Fichier > Nouveau Projet. Assure-toi iOS est sélectionné et choisissez Jeu comme modèle.

Donnez un nom à votre projet et assurez-vous que La langue est réglé sur Rapide, Technologie de jeu est réglé sur SpriteKit, et Dispositifs est réglé sur iPad.

Planification des scènes de jeu

L'une des premières choses que j'aime faire lors de la création d'un projet consiste à déterminer le nombre de scènes nécessaires au projet. J'aurai généralement au moins trois scènes: une scène d'introduction, une scène de jeu principale et une scène montrant les meilleurs scores, etc..

Pour cet exemple, nous avons simplement besoin d’une scène d’introduction et principale car nous ne garderons pas trace des vies, des scores, etc. SpriteKit contient déjà une scène lorsque vous créez un nouveau projet. Nous avons donc besoin d’une scène d’intro..

Dans le menu de Xcode, choisissez Fichier > Nouveau > Fichier. Assure-toi iOS est sélectionné et choisissez Cacao Touch Class.

Nommez la classe StartGameScene, et assurez-vous que Sous-classe de est réglé sur SKScene et La langue est réglé sur Rapide.

Configuration de GameViewController

Ouvrir GameViewController.swift. Supprimer tout le contenu de ce fichier et le remplacer par ce qui suit.

import UIKit import SpriteKit import GameplayKit, classe GameViewController: UIViewController substitue la fonction viewDidLoad () super.viewDidLoad () let scene = StartGameScene (taille: view.bounds.size) let skView = self.view as! SKView skView.showsFPS = false skView.showsNodeCount = false skView.ignoresSiblingOrder = false scene.scaleMode = .aspectFill skView.presentScene (scène) écrasement de la valeur var prefersStatusBarHidden: Bool return true 

Lorsque vous créez un nouveau projet, GameViewController.swift est configuré pour charger GameScene.sks à partir du disque. GameScene.sks est utilisé avec l'éditeur de scène intégré de SpriteKit, qui vous permet de présenter visuellement vos projets. Nous n'utiliserons pas GameScene.sks, et va au lieu de tout créer à partir de code, alors nous initions ici une nouvelle instance de StartGameScene et le présenter.

Créer la scène d'intro

Ajoutez ce qui suit à la nouvelle création StartGameScene.swift.

import UIKit import SpriteKit class StartGameScene: SKScene override func didMove (pour afficher: SKView) scene? .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) écrasera func touchesBegan (_ touches: Set, with event: UIEvent?) gardien laissez touch = touch.first else return laissez touchLocation = touch.location (dans: self) laissez touchedNode = self.atPoint (touchLocation) if (touchedNode.name == "newgame")  let newScene = GameScene (taille: taille) newScene.scaleMode = scaleMode view? .presentScene (newScene) 

Cette scène est assez simple. dans le fait bouger méthode, nous ajoutons un logo et un bouton. Puis dans toucheBegan, nous détectons des contacts sur le nouveau bouton de jeu et répondons en chargeant la scène principale GameScene.

Planification des cours

La prochaine chose que j'aime faire lors de la création d'un nouveau jeu est de décider des classes dont j'ai besoin. Je peux dire tout de suite que j'aurai besoin d'un Joueur classe et un Ennemi classe. Ces deux classes vont s'étendre SKSpriteNode. Je pense que pour ce projet, nous allons simplement créer les balles joueur et ennemi directement dans leurs classes respectives. Si vous préférez, vous pouvez créer des classes de balle de joueur et de balle ennemie séparées, et je vous suggère d'essayer de le faire vous-même.. 

Enfin, il y a les îles. Celles-ci n'ont aucune fonctionnalité spécifique mais doivent se déplacer vers le bas de l'écran. Dans ce cas, puisqu'il ne s'agit que de décorations, je pense qu'il est également correct de ne pas créer de classe, mais de simplement les créer dans le menu principal. GameScene.

Créer le Joueur Classe

Dans le menu de Xcode, choisissez Fichier > Nouveau > Fichier.  Assure-toi iOS est sélectionné et choisissez Cacao Touch Class.

Sois sûr que Classe est réglé sur Joueur, Sous-classe de: est réglé sur SKSpriteNode, et La langue est réglé sur Rapide.

Maintenant, ajoutez ce qui suit à Player.swift.

import UIKit import SpriteKit class Player: SKSpriteNode private var canFire = vrai var privé invincible = faux privé var vies: Int = 3 didSet if (lives < 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]))  

Dans le init () méthode, nous avons mis en place le corps physique et invoquer generateBullets (). le générer des balles méthode appelle à plusieurs reprises fireBullet (), qui crée une balle, définit son corps physique, et le déplace vers le bas de l'écran.

Lorsque le joueur perd une vie, le respawn () La méthode est invoquée. Dans le renaître Selon la méthode, l’avion va et vient cinq fois au cours desquels le joueur sera invincible. Un joueur a épuisé toutes les vies, le tuer() La méthode est invoquée. La méthode kill charge simplement le StartGameScene.

Créer la classe ennemie

Choisir Fichier > Nouveau > Fichier dans le menu de Xcode. Assure-toi iOS est sélectionné et choisissez Cacao Touch Class.

Sois sûr que Classe est réglé sur EnnemiSous-classe de: est réglé sur SKSpriteNode, et La langue est réglé sur Rapide.

Ajouter ce qui suit à Enemy.swift.

import UIKit import SpriteKit class Enemy: SKSpriteNode init () let texture = SKTexture (imageNamed: "ennemis1") super.init (texture: texture, couleur: .clear, taille: texture.size ()) self.name = " ennemi "self.physicsBody = SKPhysicsBody (texture: self.texture!, taille: self.size) self.physicsBody? .isDynamic = vrai self.physicsBody? .categoryBitMask = PhysicsCategories.Enemy self.physicsBody? .contactTestBestMest = PhysicsCategory PhysicsCategories.PlayerBullet self.physicsBody? .AllowsRotation = false move () generateBullets () obligatoire init? (Codeur aDecoder: NSCoder) super.init (codeur: 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 (rectangleOf: bullet.size) bullet.physicsBody ?. categoryBitMask = PhysicsCategories.EnemyBullet bullet.physicsBody? .allowsRotation = false scene? .addChild (bullet) let moveBulletAction = SKAction.move (à: 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 () let moveEnemyAction = SKAction.moveTo (y: 0 - self.size.height, durée: 12.0) let removeEnemyAction = SKAction.removeFromParent () let moveEnemySequence = SKAction.sequence ([moveEnemyAction, removeEnemyAction]) à exécuter (moveEn emySequence) func generateBullets () let fireBulletAction = SKAction.run [self faible] dans son auto? .fireBullet () let waitToFire = SKAction.wait (forDuration: 1.5) laisse fireBulletSequence = SKAction.sequence ([fireBulletAction, waitToFire] ) laissez fire = SKAction.repeatForever (fireBulletSequence) run (fire)

Cette classe est assez similaire à la Joueur classe. Nous mettons sa corps physique et invoquer generateBullets (). le bouge toi() déplace simplement l'ennemi sur l'écran.

Création de la scène de jeu principale

Supprimer tout dans GameScene.swift et ajoutez ce qui suit.

import SpriteKit import GameplayKit classe CoreMotion GameScene: SKScene, SKPhysicsContactDelegate let player = Player () let motionManager = CMMotionManager () var accelerationX: CGFloat = 0.0 annulation de la fonction didMove (pour afficher: SKView) physicsWorld.gravity = CGV. , dy: 0.0) self.physicsWorld.contactDelegate = scène personnelle? .backgroundColor = .blue physicsBody = SKPhysicsBody (edgeLoopFrom: frame) physicsBody? .categoryBitMask = PhysicsCategories.EdgeBody: physique: .CategoryBitMask = PhysicsCategories.EdgeBody.position = CGPoint (x: taille.width / 2, : player.size.height) addChild (joueur) setupAccelerometer () addEnemies () generateIslands () écrase la fonction touchBegan (_ touche: Définir, with event: UIEvent?)  func addEnemies () let generateEnemyAction = SKAction.run [moi faible] en auto? .generateEnemy () let waitToGenerateEnemy = SKAction.wait (forDuration: 3.0) let generateEnemySequence = SKAction.sequence ( [generateEnemyAction, waitToGenerateEnemy]) run (SKAction.repeatForever (generateEnemySequence)) func generateEnemy () let ennemi =) addEnfant (ennemi) ennemi.position = CGPoint (x: CGFloat (arc4random_uniform (UIDt32 (size.width - ennemi .size.width))), y: size.height - ennemis.size.height) func didBegin (_ contact: SKPhysicsContact) var premierCorps: SKPhysicsBody var deuxièmeCorps: 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)   

Nous créons une instance de Joueur et une instance de CMMotionManager. Nous utilisons l'accéléromètre pour déplacer le joueur dans ce jeu..

Dans le didMove (to :) méthode nous désactivons la gravité, mettre en place la contactDélégué, ajouter une boucle de bord et définir le joueurde la position avant de l'ajouter à la scène. Nous invoquons alors setupAccelerometer (), qui met en place l'accéléromètre, et invoque le addEnemies () et generateIslands () les méthodes.

le addEnemies () méthode appelle à plusieurs reprises le générerEnemy () méthode, qui créera une instance de Ennemi et l'ajouter à la scène.

le generateIslands () méthode fonctionne de manière similaire à la addEnemies () méthode en ce qu'il appelle à plusieurs reprises createIsland () qui crée un SKSpriteNode et l'ajoute à la scène. Dans createIsland (), nous créons aussi un SKAction qui déplace l'île dans la scène.

Dans le a commencé (_ :) méthode, nous vérifions quels nœuds sont en contact et répondons en supprimant le nœud approprié de la scène et en appelant player.die () si nécessaire. le createExplosion () method crée une animation d'explosion et l'ajoute à la scène. Une fois que l'explosion est terminée, il est retiré de la scène.

Conclusion

Au cours de cette série, nous avons appris certains des concepts les plus importants utilisés dans presque tous les jeux SpriteKit. Nous avons terminé la série en montrant à quel point il est simple de mettre en place un jeu de base. Certaines améliorations pourraient encore être apportées, telles qu'un concentrateur, des scores élevés et des sons (j'ai inclus quelques MP3 que vous pouvez utiliser à cet effet dans le référentiel). J'espère que vous avez appris quelque chose d'utile tout au long de cette série, et merci d'avoir lu!

.