SpriteKit From Scratch Physique et Collisions

introduction

Dans ce tutoriel, troisième partie de la série SpriteKit From Scratch, nous examinons en détail les fonctionnalités de simulation physique de SpriteKit et leur utilisation dans des jeux 2D SpriteKit.

Ce tutoriel nécessite que vous exécutiez Xcode 7.3 ou une version ultérieure, y compris Swift 2.2 et les SDK iOS 9.3, tvOS 9.2 et OS X 10.11.4..

Pour suivre, vous pouvez utiliser le projet que vous avez créé dans le précédent tutoriel ou télécharger une nouvelle copie à partir de GitHub..

Les graphiques utilisés pour le jeu dans cette série sont disponibles sur GraphicRiver. GraphicRiver est une excellente source pour trouver des illustrations et des graphiques pour vos jeux..

1. Mondes de la physique

La première partie de toute simulation physique dans SpriteKit est la monde physique propriété de la scène en cours. Cette propriété est un SKPhysicsWorld objet qui définit des propriétés telles que la gravité de votre scène, la vitesse de la simulation physique et le contact d'un délégué. Les mondes physiques peuvent également définir des articulations entre des objets pour épingler plusieurs nœuds ensemble à des points spécifiques..

La gravité

Pour le vue de dessus jeu de style que nous créons dans cette série, nous voulons changer la valeur de gravité par défaut fournie par SpriteKit. La gravité par défaut est destinée à un vue de face jeu avec une valeur de (0, -9,8) qui simule la gravité de la Terre, c'est-à-dire, 0 accélération horizontale et une accélération vers le bas de 9.8m / s². Pour notre jeu, nous avons besoin de 0 gravité verticale pour que la voiture ne commence pas à accélérer vers le bas une fois que nous avons défini ses propriétés physiques.

Ouvrir MainScene.sks et cliquez sur le fond gris pour sélectionner la scène. Ensuite, ouvrez le Inspecteur d'attributs et changer La gravité de sorte que les deux X et les composants sont réglés sur 0.

Il est important de noter que la gravitation est la seule propriété du monde de la physique pouvant être modifiée à l'aide de l'éditeur de scènes de Xcode. Toute autre propriété doit être modifiée par programme.

Contact délégué

Pour que le jeu détecte les collisions entre les objets, nous devons définir le monde de la physique de la scène contactDélégué propriété. Ce délégué peut être n’importe quel objet conforme à la SKPhysicsContactDelegate protocole. Ce protocole définit deux méthodes, didBeginContact (_ :) et didEndContact (_ :). Vous pouvez utiliser ces méthodes pour effectuer des actions en fonction des objets en collision dans la scène..

Pour garder notre code ensemble, nous allons faire la MainScene par exemple son propre délégué de contact. Ouvrir MainScene.swift et éditer le MainScene définition de classe pour se conformer à la SKPhysicsContactDelegate protocole.

import UIKit import SpriteKit class MainScene: SKScene, SKPhysicsContactDelegate …

Dans didMoveToView (_ :), nous avons mis le MainScene par exemple en tant que délégué de contact du monde physique propriété.

écrasé func didMoveToView (vue: SKView) … physicsWorld.contactDelegate = self

Nous allons mettre en œuvre les méthodes du SKPhysicsContactDelegate protocole plus tard. Nous devons d’abord définir les propriétés physiques des nœuds de la scène..

2. Corps de physique

Chaque nœud de SpriteKit sur lequel vous souhaitez simuler la physique d’une manière ou d’une autre doit recevoir un code unique. SKPhysicsBody objet. Les corps physiques contiennent plusieurs propriétés, notamment:

  • Masse
  • densité
  • surface
  • friction
  • rapidité

Dans vos jeux, vous pouvez également définir jusqu'à 32 catégories uniques et un corps physique peut être affecté à un nombre quelconque de ces catégories. Les catégories sont très utiles pour déterminer quels nœuds de votre scène peuvent interagir en termes de collisions.

Sur les corps de physique, ces catégories sont représentées par les catégorieBitMask et collisionBitMask propriétés, qui sont à la fois donné la 0xFFFFFFFF valeur par défaut. Cela signifie que tous les nœuds appartiennent à toutes les catégories. Il est important de noter que dans cette valeur, chaque chiffre hexadécimal F est une forme abrégée et représente le nombre 15 en chiffres binaires (1111) dont chacune correspond à l'une des 32 catégories que vous pouvez utiliser.

Lorsque deux nœuds entrent en collision, une logique ET l'opération est effectuée sur le collisionBitMask et le catégorieBitMask des premier et deuxième corps respectivement. Si le résultat est une valeur différente de zéro, SpriteKit effectue sa simulation sur les deux nœuds auxquels les corps appartiennent..

Notez que cela ET le calcul est effectué deux fois avec les deux corps échangés. Par exemple:

  • Calcul 1: bodyA.collisionBitMask & bodyB.categoryBitMask
  • Calcul 2: bodyB.collisionBitMask & bodyA.categoryBitMask

Si vous ne savez pas comment ET L’opérateur fonctionne, alors voici un exemple très simple écrit en Swift:

let mask1 = 0x000000FF let mask2 = 0x000000F0 let result = masque1 & mask2 // resultat = 0x000000F0

le ET l'opérateur détermine quelles parties des masques de bits sont identiques et renvoie une nouvelle valeur de masque de bits contenant les parties correspondantes.

Une chose importante à noter est que ces masques de bits n'affectent que le côté SpriteKit de la simulation physique et que vous n'êtes pas averti des collisions détectées de cette manière. Cela signifie que les organes peuvent interagir les uns avec les autres mais aucune des méthodes du délégué de contact n'est appelée.

Pour que ces méthodes soient exécutées, vous devez spécifier un contactTestBitMask pour chaque corps, ce qui produit une valeur non nulle quand un ET l'opérateur agit sur eux. Pour tous les corps physiques, ce masque binaire a une valeur par défaut de 0x00000000 ce qui signifie que vous ne serez pas informé des collisions auxquelles l'organisme de physique prend part.

Les corps physiques, y compris leurs divers masques de bits, peuvent être configurés dans l'éditeur de scène Xcode. Ouvrir MainScene.sks, sélectionnez la voiture et ouvrez le Inspecteur d'attributs sur la droite. Faites défiler jusqu'à la Définition de la physique section.

Parce que Type de corps est réglé sur Aucun, aucune des propriétés liées à la physique n'est visible. Pour changer cela, nous devons définir Type de corps à une valeur autre que Aucun. Trois types de corps sont disponibles:

  • rectangle de délimitation
  • cercle de délimitation
  • masque alpha
Th

Ces trois types de corps physiques sont les plus courants dans SpriteKit. Rectangle englobant et Cercle de reliure travaillez en créant une barrière autour de l’image-objet à utiliser dans les simulations physiques. Cela signifie que l'image-objet entre en collision avec un autre nœud chaque fois que sa forme englobante heurte le corps physique d'un autre nœud..

Le bord d'un rectangle de délimitation est exactement identique à la taille du nœud indiquée dans l'éditeur de scène. Si vous sélectionnez Cercle de reliure, cependant, vous voyez un mince cercle bleu clair représentant la forme du cercle de délimitation.

Masque alpha fonctionne un peu différemment et examine la texture réelle de l'image-objet pour déterminer les contours du corps physique. Ce type de corps est de loin le plus précis de SpriteKit, mais il peut avoir un impact important sur les performances de votre jeu, en particulier lorsque vous utilisez des sprites aux formes complexes..

Pour notre jeu, comme nous n’utilisons qu’un sprite de voiture et que notre scène n’est pas particulièrement complexe, nous allons utiliser la Masque alpha type de corps. Il est ne pas Il est recommandé d'utiliser ce type de corps pour tous les sprites de votre scène, même s'il est le plus précis. Lorsque vous sélectionnez cette option dans le menu déroulant, une ligne bleu clair apparaît autour du bord de la voiture..

Il est important de noter que d’autres types d’organes de physique peuvent être créés par programme, tels que des CGPath objets ainsi que des cercles et des rectangles de tailles personnalisées.

Toujours dans le Inspecteur d'attributs, vous devriez maintenant voir plus d’options à votre disposition dans Définition de la physique section. La seule propriété que nous devons changer est le Masque de contact. Changez ceci en une valeur de 1.

Avec le corps physique de la voiture mis en place, nous pouvons commencer à mettre quelques obstacles dans le jeu pour entrer en collision avec la voiture.

3. Détecter les collisions

Avant de mettre en œuvre les méthodes du SKPhysicsContactDelegate protocole, nous devons ajouter quelques obstacles pour éviter la voiture. Pour ce faire, nous allons générer un nouvel obstacle toutes les trois secondes devant la voiture et placer l'obstacle dans une voie aléatoire..

Ouvrir MainScene.swift et ajouter une déclaration d'importation pour le GameplayKit cadre afin que nous puissions utiliser les générateurs de nombres aléatoires fournis par GameplayKit.

importer GameplayKit

Ensuite, ajoutez la méthode suivante à la MainScene classe:

func spawnObstacle (timer: NSTimer) si player.hidden timer.invalidate () return laisse spriteGenerator = GKShuffledDistribution (lowerValue: 1, mostValue: 2) laisse obstacle = SKSpriteNode (imageNamed: "Obstacle \ (spriteGenerator). ") obstacle.xScale = 0.3 obstacle.yScale = 0.3 let physicsBody = SKPhysicsBody (circleOfRadius: 15) physicsBody.contactTestBitMask = 0x00000001 physicsBody.pinned = true physicsBody.allowsRotation = false obstacle.physicsBody = physicsBody = centre difference = CGFloat (85.0) var x: CGFloat = 0 let laneGenerator = GKShuffledDistribution (valeur minimale: 1, valeur maximale: 3) commutateur laneGenerator.nextInt () cas 1: x = centre - cas différent 2: x = centre - cas différent: 2 = centre + différence par défaut: fatalError ("Nombre hors de [1, 3] généré") obstacle.position = CGPoint (x: x, y: (player.position.y + 800)) addChild (obstacle)

Cette méthode est appelée toutes les trois secondes. Décomposons pour voir ce qui se passe. Si le nœud du joueur actuel est masqué, ce qui est vrai lorsque la voiture heurte un obstacle, nous invalidons le chronomètre et nous arrêtons de créer des obstacles..

Nous obtenons un nombre aléatoire entre 1 et 2, et utilisez-le pour créer un noeud d’image-objet avec l’un des deux objets-objets d’obstacles disponibles dans le projet. Nous modifions ensuite l’échelle de l’obstacle afin qu’elle soit suffisamment petite pour que la voiture puisse manœuvrer..

Ensuite, nous créons un corps physique pour ce nouvel obstacle avec un cercle de rayon 15 et un masque de contact de 0x00000001. Nous fixons épinglé à vrai et permetRotation à faux afin que l'obstacle reste en place et ne bouge pas. Le corps physique est alors affecté à l'obstacle.

Nous générons un autre nombre aléatoire entre 1 et 3 déterminer dans quelle voie l'obstacle doit être placé et lui donner sa position calculée en l'ajoutant à la scène.

Notez que la différence horizontale, 85, utilisé dans spawnObstacle (_ :) est différent de celui utilisé lors du déplacement de la voiture, 70. Nous faisons cela pour donner un peu plus d’espace à la voiture pour qu’elle se déplace entre les obstacles.

Avec la logique de génération d’obstacles en place, nous pouvons ajouter le code suivant à la fin de la didMoveToView (_ :) méthode.

override func didMoveToView (view: SKView) … let timer = NSTimer (timeInterval: 3.0, target: self, sélecteur: #selector (spawnInObstacle (_ :)), userInfo: nil, répète: true) NSRunLoop.mainRunLoop (). addTimer (timer, forMode: NSRunLoopCommonModes) let camera = SKCameraNode () self.camera = caméra camera.position = CGPoint (x: centre, y: player.position.y + 200) laisse moveForward = SKAction.moveBy (CGVectorMake (0, 100 ), durée: 1.0) camera.runAction (SKAction.repeatActionForever (moveForward)) addChild (camera) player.xScale = 0.4; player.yScale = 0.4 // Réduit la taille de la voiture pour qu'elle soit mieux ajustée entre les obstacles

Nous créons une minuterie pour exécuter spawnObstacle (_ :) toutes les trois secondes et ajoutez-le à la boucle principale. Nous créons également un SKCameraNode agir en tant que caméra pour la scène et l'assigner à la caméra propriété de la scène. Cela provoque le rendu de la scène du point de vue de ce nœud de caméra. Notez que la caméra est centrée horizontalement et légèrement au-dessus de la voiture.

Nous ajoutons également une action identique à la caméra pour qu'elle reste alignée avec la voiture. Nous ajoutons la caméra en tant que nœud enfant de la scène comme tout autre nœud normal. Dernier point mais non le moindre, nous réduisons la voiture afin qu’elle puisse mieux s’insérer entre les obstacles.

La dernière partie de la détection de collision implémente l’un des deux SKPhysicsContactDelegate méthodes de protocole. Dans notre cas, nous allons mettre en œuvre le didBeginContact (_ :) méthode car nous voulons être avertis dès que la voiture heurte un obstacle. Ajoutez la méthode suivante à la MainScene classe.

func didBeginContact (contact: SKPhysicsContact) if contact.bodyA.node == player || contact.bodyB.node == player player.hidden = true joueur.removeAllActions () caméra? .removeAllActions ()

Vous pouvez voir que cette méthode a un SKPhysicsContact paramètre passé à elle. Cet objet contient des informations clés sur la collision, y compris sa direction, son impulsion et les objets impliqués..

Dans ce code, nous nous intéressons uniquement aux nœuds impliqués dans la collision. Nous vérifions si l'un d'eux était la voiture et, le cas échéant, cachons la voiture dans la scène et mettons fin au mouvement de la voiture et de la caméra..

Construisez et exécutez votre application et jouez à votre jeu. Vous verrez que, lorsque vous rencontrez un obstacle, la voiture disparaît et la scène cesse de bouger..

Conclusion

Vous devez maintenant savoir comment configurer les corps physiques des noeuds de votre scène et les utiliser pour simuler une physique réaliste. Vous devez également être à l'aise pour configurer la détection de collision dans votre scène en définissant un délégué de contact et en affectant des masques de bits de test de contact aux nœuds que vous prévoyez d'entrer en collision..

Dans le prochain tutoriel de SpriteKit From Scratch, nous allons examiner les fonctionnalités visuelles plus avancées de SpriteKit, notamment les systèmes de particules, les lumières et les filtres..

Comme toujours, assurez-vous de laisser vos commentaires dans les commentaires ci-dessous.