Sous-classs SKNodes créées avec le file de scène SpriteKit .sks

(ceci est pour XCode 6 et iOS 8 beta 4)

J'adore le nouvel éditeur de SceneKit. Je charge avec succès la scène du file .sks dans une class SKScene personnalisée. Cependant, les objects qui s'y trouvent sont instanciés en tant que classs par défaut (SKNode, SKSpriteNode, etc), et je ne sais pas comment les lier pour être instanciés en tant que sous-classs personnalisées.

Actuellement, je contourne cela en créant des classs personnalisées et en créant des liens vers des nœuds de sprites en tant que propriété, et cela fonctionne bien

J'ai écrit un petit assistant pour traiter ceci: https://github.com/ice3-software/node-archive-delegate . Il utilise NSKeyedUnarchiverDelegate pour sous- NSKeyedUnarchiverDelegate vos sprites par nom.

Actuellement, vous devez le faire par son nom dans la méthode ajoutée aux templates de jeu SpriteKit. Ils traitent de ce sujet dans la video sur les meilleures pratiques de SpriteKit dans WWDC 2014. Il est facile de passer à côté de la video parce qu'elle en a beaucoup.

Voici la méthode.

 + (instancetype)unarchiveFromFile:(NSSsortingng *)file { /* Resortingeve scene file path from the application bundle */ NSSsortingng *nodePath = [[NSBundle mainBundle] pathForResource:file ofType:@"sks"]; /* Unarchive the file to an SKScene object */ NSData *data = [NSData dataWithContentsOfFile:nodePath options:NSDataReadingMappedIfSafe error:nil]; NSKeyedUnarchiver *arch = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; [arch setClass:self forClassName:@"SKScene"]; SKScene *scene = [arch decodeObjectForKey:NSKeyedArchiveRootObjectKey]; [arch finishDecoding]; return scene; } 

C'est une catégorie sur SKScene qui inclut une méthode pour utiliser NSKeyedUnarchiver pour substituer la class lorsqu'elle est chargée à partir du file .sks dans le mainBundle. Dans iOS, ils l'ajoutent au file GameViewController.m et dans OS X ils l'ajoutent au file AppDelegate.m .

Ici ou dans vos sous-classs SKNode individuelles, vous pouvez implémenter ceci. C'est ce qu'il a fait ci-dessous dans son message. Ceci a été fourni par Apple et couvert dans la video WWDC. Je suppose que l'année prochaine, il sera mieux géré. Entre-time, déposez un bug demandant à SKNodes d'get quelque chose comme IBDesignable pour Scene Editor. 🙂

J'ai fait un petit truc pour utiliser l'éditeur de SceneKit, et je vais essayer de l'utiliser mais je ne suis pas sûr de savoir comment cela peut réduire les performances. Je veux utiliser l'éditeur de scène pour créer des structures SKNodes complexes et les charger dans la scène actuelle. Il pourrait également aider avec des noeuds de sous-classment.

Je configure mon noeud dans l'éditeur de scène, définit le noeud parent comme un noeud vide appelé "base" et fait une sous-class de SKNode. Ensuite, j'ai fait une méthode init et je l'appelle quand j'en ai besoin dans ma scène:

 // subclass code class MyOwnSKNodeSubclass: SKNode { let nodeLayer = SKNode() init(fromNode: SKNode){ super.init() nodeLayer.addChild(fromNode.childNodeWithName("base").copy() as SKNode) addChild(nodeLayer) } } // scene code if let myNode = SKNode.unarchiveNodeFromFile("MyScene") { // you can use your subclass here let node = MyOwnSKNodeSubclass(fromNode: myNode) addChild(node) } 

J'ai aussi utilisé ma propre extension SKNode, pas une grosse différence mais:

 class func unarchiveNodeFromFile(file:Ssortingng) -> SKNode?{ if let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks") { var nodeData = NSData.dataWithContentsOfFile(path, options: .DataReadingMappedIfSafe, error: nil) var archiver = NSKeyedUnarchiver(forReadingWithData: nodeData) archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKNode") let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as SKNode archiver.finishDecoding() return scene } else { return nil } } 

Comme je l'ai dit, je ne suis pas sûr de la productivité, mais je suppose que cela ne nuira pas trop si vous ne l'utilisez pas très souvent. J'espère que cela aide quelqu'un.

Oui, Apple devrait faciliter cela pour tous, mais pour le moment, voici la solution la plus viable pour mes besoins:

Éviter le sous-classment

Bien sûr, cela n'est peut-être pas possible, mais dans mon cas, la sous-class que j'avais en tête contient une logique pour contrôler les charts que j'ai disposés dans le file SKS … Des sons terriblement proches de ViewController, n'est-ce pas?

J'ai créé une class OverlayController et je l'initialise avec:

 self.childNodeWithName(Outlet.OverlayNode)! 

Alors maintenant, le nœud de recouvrement est juste un nœud bête, et le controller est la sous-class à part entière qui a tous les goodies.

Mais il y a plus

Juste jeter cela pour adoucir l'affaire:

 private extension SKNode { var progressBar: SKNode { return self.childNodeWithName("ProgressBar")! } } 

Ceci est une extension privée dans le nouveau file de class de controller, de sorte que nous pouvons accéder sans douleur aux enfants de l'idiot SKNode .

Point de la douleur

Un point certes douloureux est la manipulation tactile. Il est naturel de sous-classr un SKNode pour faire des manipulations tactiles personnalisées, et l'approche de la composition ne fait pratiquement rien sur ce front. J'envoie des retouches de la scène pour le moment, mais je publierais des mises à jour s'il y avait une meilleure façon de faire.