SpriteKit From Scratch: Techniques avancées et optimisations

introduction

Dans ce didacticiel, le cinquième et dernier volet de la série SpriteKit From Scratch, nous examinons quelques techniques avancées que vous pouvez utiliser pour optimiser vos jeux basés sur SpriteKit afin d’améliorer les performances et l’expérience utilisateur.

Ce didacticiel nécessite que vous exécutiez Xcode 7.3 ou version ultérieure, qui inclut Swift 2.2 et les SDK iOS 9.3, tvOS 9.2 et OS X 10.11.4. Pour suivre, vous pouvez soit utiliser le projet que vous avez créé dans le didacticiel précédent, soit télécharger une nouvelle copie depuis GitHub.

Les graphiques utilisés pour le jeu de cette série se trouvent sur GraphiqueRiver. GraphicRiver est une excellente source pour trouver des illustrations et des graphiques pour vos jeux.

1. Atlas de textures

Afin d’optimiser l’utilisation de la mémoire de votre jeu, SpriteKit fournit la fonctionnalité d’atlas de textures sous la forme de SKTextureAtlas classe. Ces atlas combinent efficacement les textures que vous spécifiez en une seule et grande texture qui prend moins de mémoire que les textures individuelles seules.

Heureusement, Xcode peut créer des atlas de textures très facilement pour vous. Cela se fait dans les mêmes catalogues d’actifs que ceux utilisés pour d’autres images et ressources de vos jeux. Ouvrez votre projet et accédez au Actifs.xcassets catalogue d’actifs. En bas de la barre latérale gauche, cliquez sur l’icône + et sélectionnez le Nouvel Atlas des Sprites option.

Créer un nouvel atlas de sprites

En conséquence, un nouveau dossier est ajouté au catalogue d’actifs. Cliquez une fois sur le dossier pour le sélectionner et cliquez à nouveau pour le renommer. Nomme le Obstacles. Ensuite, faites glisser le Obstacle 1 et Obstacle 2 ressources dans ce dossier. Vous pouvez également supprimer le blanc Lutin actif que Xcode génère si vous le souhaitez, mais ce n’est pas obligatoire. Une fois terminé, votre Obstacles l’atlas de texture devrait ressembler à ceci:

Atlas de texture d'obstacles

Il est maintenant temps d’utiliser l’atlas de textures dans le code. Ouvert MainScene.swift et ajoutez la propriété suivante au MainScene classe. Nous initialisons un atlas de textures en utilisant le nom que nous avons entré dans notre catalogue d’actifs.

Bien que cela ne soit pas nécessaire, vous pouvez précharger les données d’un atlas de textures en mémoire avant de l’utiliser. Cela permet à votre jeu d’éliminer tout décalage qui pourrait se produire lors du chargement de l’atlas de textures et de la récupération de la première texture. Le préchargement d’un atlas de textures se fait avec une seule méthode et vous pouvez également exécuter un bloc de code personnalisé une fois le chargement terminé.

dans le MainScene classe, ajoutez le code suivant à la fin de la didMoveToView(_:) méthode:

Pour récupérer une texture à partir d’un atlas de textures, vous utilisez le textureNamed(_:) méthode avec le nom que vous avez spécifié dans le catalogue d’actifs en tant que paramètre. Mettons à jour le spawnObstacle(_:) méthode dans le MainScene class pour utiliser l’atlas de textures que nous avons créé il y a un instant. Nous récupérons la texture de l’atlas de textures et l’utilisons pour créer un nœud de sprite.

Notez que si votre jeu tire parti des ressources à la demande (ODR), vous pouvez facilement spécifier une ou plusieurs balises pour chaque atlas de textures. Une fois que vous avez accédé aux bonnes balises de ressources avec les API ODR, vous pouvez ensuite utiliser votre atlas de textures comme nous l’avons fait dans le spawnObstacle(_:) méthode. Vous pouvez en savoir plus sur les ressources à la demande dans un autre de mes tutoriels.

2. Sauvegarde et chargement de scènes

SpriteKit vous offre également la possibilité de sauvegarder et de charger facilement des scènes depuis et vers un stockage persistant. Cela permet aux joueurs de quitter votre jeu, de le relancer plus tard et d’être toujours au même stade de votre jeu qu’avant.

La sauvegarde et le chargement de votre jeu sont gérés par le NSCoding protocole, que le SKScene la classe est déjà conforme à. L’implémentation par SpriteKit des méthodes requises par ce protocole permet automatiquement à tous les détails de votre scène d’être enregistrés et chargés très facilement. Si vous le souhaitez, vous pouvez également remplacer ces méthodes pour enregistrer certaines données personnalisées avec votre scène.

Parce que notre jeu est très basique, nous allons utiliser un simple Bool valeur pour indiquer si la voiture s’est écrasée. Cela vous montre comment enregistrer et charger des données personnalisées liées à une scène. Ajoutez les deux méthodes suivantes du NSCoding protocole au MainScene classe.

Si vous ne connaissez pas le NSCoding protocole, le encodeWithCoder(_:) gère la sauvegarde de votre scène et de l’initialiseur avec un seul NSCoder Le paramètre gère le chargement.

En relation :  Ionic From Scratch: Travailler avec des composants ioniques

Ensuite, ajoutez la méthode suivante au MainScene classe. le saveScene() méthode crée un NSData représentation de la scène, en utilisant le NSKeyedArchiver classe. Pour simplifier les choses, nous stockons les données dans NSUserDefaults.

Ensuite, remplacez la mise en œuvre de didBeginContactMethod(_:) dans le MainScene classe avec ce qui suit:

La première modification apportée à cette méthode est la modification du nœud du joueur categoryBitMask plutôt que de le supprimer entièrement de la scène. Cela garantit que lors du rechargement de la scène, le nœud du joueur est toujours là, même s’il n’est pas visible, mais que les collisions en double ne sont pas détectées. L’autre changement effectué est d’appeler le saveScene() méthode que nous avons définie précédemment une fois que la logique d’explosion personnalisée a été exécutée.

Enfin, ouvrez ViewController.swift et remplacez le viewDidLoad() méthode avec l’implémentation suivante:

Lors du chargement de la scène, nous vérifions d’abord s’il y a des données enregistrées dans le standard NSUserDefaults. Si tel est le cas, nous récupérons ces données et recréons le MainScene objet utilisant le NSKeyedUnarchiver classe. Sinon, nous obtenons l’URL du fichier de scène que nous avons créé dans Xcode et nous en chargeons les données de la même manière.

Exécutez votre application et rencontrez un obstacle avec votre voiture. À ce stade, vous ne voyez pas de différence. Exécutez à nouveau votre application, cependant, et vous devriez voir que votre scène a été restaurée exactement comme elle était lorsque vous venez de planter la voiture.

3. La boucle d’animation

Avant le rendu de chaque image de votre jeu, SpriteKit exécute une série de processus dans un ordre particulier. Ce groupe de processus est appelé boucle d’animation. Ces processus tiennent compte des actions, des propriétés physiques et des contraintes que vous avez ajoutées à votre scène.

Si, pour une raison quelconque, vous devez exécuter du code personnalisé entre l’un de ces processus, vous pouvez soit remplacer certaines méthodes spécifiques de votre SKScene sous-classe ou spécifiez un délégué conforme à la SKSceneDelegate protocole. Notez que, si vous affectez un délégué à votre scène, les implémentations de classe des méthodes suivantes ne sont pas appelées.

Les processus de boucle d’animation sont les suivants:

Étape 1

La scène appelle son update(_:) méthode. Cette méthode a un seul NSTimeInterval paramètre, qui vous donne l’heure actuelle du système. Cet intervalle de temps peut être utile car il vous permet de calculer le temps nécessaire au rendu de votre image précédente.

Si la valeur est supérieure à 1 / 60e de seconde, votre jeu ne fonctionne pas aux 60 images par seconde (FPS) que SpriteKit vise. Cela signifie que vous devrez peut-être modifier certains aspects de votre scène (par exemple, les particules, le nombre de nœuds) pour réduire sa complexité.

Étape 2

La scène exécute et calcule les actions que vous avez ajoutées à vos nœuds et les positionne en conséquence.

Étape 3

La scène appelle son didEvaluateActions() méthode. C’est ici que vous pouvez exécuter n’importe quelle logique personnalisée avant que SpriteKit ne continue avec la boucle d’animation.

Étape 4

La scène effectue ses simulations physiques et modifie votre scène en conséquence.

Étape 5

La scène appelle son didSimulatePhysics() , que vous pouvez remplacer avec la didEvaluateActions() méthode.

Étape 6

La scène applique les contraintes que vous avez ajoutées à vos nœuds.

Étape 7

La scène appelle son didApplyConstraints() méthode, que vous pouvez remplacer.

Étape 8

La scène appelle son didFinishUpdate() méthode, que vous pouvez également remplacer. Il s’agit de la dernière méthode dans laquelle vous pouvez modifier votre scène avant que son apparence pour cette image ne soit finalisée.

Étape 9

Enfin, la scène rend son contenu et met à jour son contenant SKView en conséquence.

Il est important de noter que si vous utilisez un SKSceneDelegate objet plutôt qu’une sous-classe personnalisée, chaque méthode gagne un paramètre supplémentaire et change légèrement son nom. Le paramètre supplémentaire est un SKScene object, qui vous permet de déterminer la scène avec laquelle la méthode est exécutée. Les méthodes définies par le SKSceneDelegate protocole sont nommés comme suit:

  • update(_:forScene:)
  • didEvaluateActionsForScene(_:)
  • didSimulatePhysicsForScene(_:)
  • didApplyConstraintsForScene(_:)
  • didFinishUpdateForScene(_:)

Même si vous n’utilisez pas ces méthodes pour apporter des modifications à votre scène, elles peuvent toujours être très utiles pour le débogage. Si votre jeu est constamment en retard et que la fréquence d’images diminue à un moment particulier de votre jeu, vous pouvez remplacer toute combinaison des méthodes ci-dessus et trouver l’intervalle de temps entre chacune d’elles. Cela vous permet de déterminer avec précision si ce sont précisément vos actions, votre physique, vos contraintes ou vos graphiques qui sont trop complexes pour que votre jeu fonctionne à 60 FPS.

En relation :  9 applications mobiles amusantes pour changer la couleur de vos cheveux en photos

4. Meilleures pratiques de performance

Dessin par lots

Lors du rendu de votre scène, SpriteKit, par défaut, parcourt les nœuds de votre scène children tableau et les dessine sur l’écran dans le même ordre qu’ils sont dans le tableau. Ce processus est également répété et mis en boucle pour tous les nœuds enfants qu’un nœud particulier peut avoir.

L’énumération individuelle des nœuds enfants signifie que SpriteKit exécute un appel de dessin pour chaque nœud. Alors que pour les scènes simples, cette méthode de rendu n’a pas d’impact significatif sur les performances, à mesure que votre scène gagne plus de nœuds, ce processus devient très inefficace.

Pour rendre le rendu plus efficace, vous pouvez organiser les nœuds de votre scène en couches distinctes. Cela se fait via le zPosition propriété du SKNode classe. Plus un nœud est haut zPosition c’est-à-dire que plus il est “proche” de l’écran, ce qui signifie qu’il est rendu au-dessus des autres nœuds de votre scène. De même, le nœud avec le plus bas zPosition dans une scène apparaît tout à fait “en arrière” et peut être chevauché par n’importe quel autre nœud.

Après avoir organisé les nœuds en couches, vous pouvez définir un SKView objets ignoreSiblingOrder propriété à true. Cela se traduit par SpriteKit en utilisant le zPosition valeurs pour rendre une scène plutôt que l’ordre de la children tableau. Ce processus est beaucoup plus efficace que tous les nœuds avec le même zPosition sont regroupés en un seul appel de tirage au lieu d’en avoir un pour chaque nœud.

Il est important de noter que le zPosition la valeur d’un nœud peut être négative si nécessaire. Les nœuds de votre scène sont toujours rendus par ordre croissant zPosition.

Évitez les animations personnalisées

Les deux SKAction et SKConstraint Les classes contiennent un grand nombre de règles que vous pouvez ajouter à une scène pour créer des animations. Faisant partie du framework SpriteKit, ils sont optimisés autant que possible et s’intègrent parfaitement dans la boucle d’animation de SpriteKit.

Le large éventail d’actions et de contraintes qui vous est fourni permet presque toutes les animations possibles que vous pourriez souhaiter. Pour ces raisons, il est recommandé de toujours utiliser des actions et des contraintes dans vos scènes pour créer des animations plutôt que d’exécuter une logique personnalisée ailleurs dans votre code.

Dans certains cas, en particulier si vous avez besoin d’animer un groupe de nœuds raisonnablement grand, les champs de force physique peuvent même produire le résultat souhaité. Les champs de force sont encore plus efficaces car ils sont calculés avec le reste des simulations physiques de SpriteKit.

Masques de bits

Vos scènes peuvent être encore plus optimisées en utilisant uniquement les masques de bits appropriés pour les nœuds de votre scène. En plus d’être cruciaux pour la détection des collisions physiques, les masques binaires déterminent également comment les simulations physiques et l’éclairage réguliers affectent les nœuds d’une scène.

Pour n’importe quelle paire de nœuds dans une scène, qu’ils se heurtent ou non, SpriteKit surveille où ils sont les uns par rapport aux autres. Cela signifie que, s’il reste avec les masques par défaut avec tous les bits activés, SpriteKit garde une trace de l’emplacement de chaque nœud dans votre scène par rapport à tous les autres nœuds. Vous pouvez grandement simplifier les simulations physiques de SpriteKit en définissant des masques de bits appropriés afin que seules les relations entre les nœuds susceptibles de se heurter soient suivies.

De même, une lumière dans SpriteKit n’affecte un nœud que si la logique AND de leurs masques de bits de catégorie est une valeur non nulle. En modifiant ces catégories, de sorte que seuls les nœuds les plus importants de votre scène soient affectés par une lumière particulière, vous pouvez réduire considérablement la complexité d’une scène.

Conclusion

Vous devriez maintenant savoir comment optimiser davantage vos jeux SpriteKit en utilisant des techniques plus avancées, telles que les atlas de texture, le dessin par lots et les masques de bits optimisés. Vous devez également être à l’aise avec l’enregistrement et le chargement de scènes pour offrir à vos joueurs une meilleure expérience globale.

Tout au long de cette série, nous avons examiné de nombreuses fonctionnalités et fonctionnalités du framework SpriteKit sous iOS, tvOS et OS X. Il existe des sujets encore plus avancés au-delà de la portée de cette série, tels que les shaders OpenGL ES et Metal personnalisés. comme champs physiques et articulations.

Si vous souhaitez en savoir plus sur ces sujets, je vous recommande de commencer par le Référence du framework SpriteKit et renseignez-vous sur les classes pertinentes.

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

Moyens Staff
Moyens I/O Staff vous a motivé, donner des conseils sur la technologie, le développement personnel, le style de vie et des stratégies qui vous aider.