18

Hi I am trying to remove all nodes from my Scenekit scene but I cannot for the life of me figure out a way.

It seems logical to me that there must be a function for doing this automatically but I cannot find it.

In context, I am trying to remove all nodes so I can reset my scene, which will happen reasonably often. Perhaps there is another way of doing this and I would be fine with that, I'm not stuck with having to remove all nodes.

Thanks!

Tim Andrews
  • 827
  • 1
  • 7
  • 21

8 Answers8

41

Try this (assuming you are using Swift):

rootNode.enumerateChildNodes { (node, stop) in
        node.removeFromParentNode()
    }

Works for me.

AW5
  • 406
  • 3
  • 12
Alan
  • 466
  • 5
  • 5
  • 2
    Note that per the Cocoa conventions it is a programmer error to mutate a collection (the child nodes) while it's being enumerated. I would not recommend doing that. – mnuages Sep 10 '19 at 12:27
15

For me worked like below:

sceneView.scene.rootNode.enumerateChildNodes { (node, stop) in
node.removeFromParentNode() }
Arunabh Das
  • 13,212
  • 21
  • 86
  • 109
Alessandro Mattiuzzi
  • 2,309
  • 2
  • 18
  • 24
3

you can either create a new scene or call -[SCNNode removeFromParentNode] on every child node of the scene's rootNode

mnuages
  • 13,049
  • 2
  • 23
  • 40
  • I moved my accepted answer from this to Alans answer, partly because his is clearer but mostly because it is in swift which is what I tagged the question with. – Tim Andrews Sep 05 '19 at 05:15
3

Where you need to remove all of your nodes, call this (if your scene isn't self, change it):

for (SCNNode *node in [self children]) {
    [node removeFromParent]
}

Additionally, if you need to remove each node except for some, call this (say, we don't want to remove 3 nodes, and they're named a, b, and c)

for (SCNNode *node in [self children]) {
    if (![node.name isEqualToString:@"a"] && ![node.name isEqualToString:@"b"] && ![node.name isEqualToString:@"c"]) {
        [node removeFromParent]
    }
}

Hope this helps!

DDPWNAGE
  • 1,423
  • 10
  • 37
1

For some reason, every single answer on the topic I could find features SCNNode.enumerateChildNodes method, but using it has a significant downside — it is asynchronous. Meaning you could not be notified when all of node's children had been removed.

Fortunately, there is much more robust approach which takes advantage of childNodes(passingTest:) method. It basically allows you to retrieve all nodes that satisfy a condition, synchronously.

So removal of all child nodes could be achieved in two steps:

// baseNode: SCNNode is defined somewhere in your code

// 1. retrieve all child nodes
let allChildNodes = baseNode.childNodes { _, _ in true }

// 2. remove nodes from their parent
for childNode in allChildNodes {
  childNode.removeFromParentNode()
}

Note that we could use the first param of the block for more advanced filtering — say selecting nodes by their name, contents etc.

Nikandr Marhal
  • 1,230
  • 1
  • 12
  • 12
0

Here is a solution in Objective-C (Yes it still exists!)

while (self.sceneView.scene.rootNode.childNodes.count) {
    NSArray<SCNNode *> *nodes = self.sceneView.scene.rootNode.childNodes;
    [nodes[0] removeFromParentNode];
}
Hecot
  • 89
  • 1
  • 11
0

Modifying a collection while looping through it is not good practice; here's an alternative:

while let n = node.childNodes.first { n.removeFromParentNode() }
Nestor
  • 2,753
  • 2
  • 29
  • 34
-1

the simplest way I found to remove all nodes from a scene is:

  self.removeAllChildren()

This worked well for me in XCode version 7.2

Jason
  • 93
  • 9