Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpriteKit: find all descendants of SKNode of certain class?

This question shows how to find all children of a SKNode that belong to a certain class, but what if we want all descendants (e.g., grandchildren) that belong to a certain class?

Is there a native way to do this in SpriteKit, or is the only option to create a recursive form of the solution from the aforementioned question?

The SKNode documentation highlights a search function that lets you find descendants with a certain name, but is there a way to filter descendants by class and not be name? We don't want to assign names to nodes if avoidable.

We're using Swift 3.

like image 540
Crashalot Avatar asked May 31 '17 01:05

Crashalot


2 Answers

Just add this extension to your project

import SpriteKit

extension SKNode {
    func allDescendants<Element: SKNode>(byType type: Element.Type) -> [Element] {
        let currentLevel:[Element] = children.flatMap { $0 as? Element }
        let moreLevels:[Element] = children.reduce([Element]()) { $0 + $1.allDescendants(byType: type) }
        return currentLevel + moreLevels
    }
}

Now you can fetch all the descendants of an SKNode having a specific type (e.g. SKSpriteNode) writing

let descendants = node.allDescendants(byType: SKSpriteNode.self)

Example

class Enemy: SKSpriteNode { }

let root = SKNode()
let a = Enemy()
let b = SKNode()
let c = SKNode()
let d = Enemy()

root.addChild(a)
root.addChild(b)
a.addChild(c)
a.addChild(d)

let enemies: [Enemy] = root.allDescendants(byType: Enemy.self)

print(enemies.count) // 2
like image 188
Luca Angeletti Avatar answered Nov 13 '22 14:11

Luca Angeletti


What we did was pass a block to the SKNode function that finds nodes by name, and used * as the search term to avoid assigning a name to desired nodes.

    var descendants = [CustomClass]()
    nodeToSearch.enumerateChildNodes(withName: ".//*") { node, stop in
        if node is CustomClass {
            descendants.append(node as! CustomClass)
        }
    }
like image 35
Crashalot Avatar answered Nov 13 '22 13:11

Crashalot