Jasmeet Kaur
Jasmeet Kaur

Reputation: 1568

Adding SCNNode multiple time shows only once

I am trying to add SCNNode mutiple time in a loop at different position but I can see same type of node at once with the last position.

Below is the code

let entityArray:[entity] = [.coin, .coin, .coin, .brick, .coin, .coin, .coin, .brick]

func setupworld() {
    let scene = SCNScene(named: "art.scnassets/MainScene.scn")!

    var zPosition = -10
    var count = 0
    let delta = -4

    for entity in entityArray {

        var node = SCNNode()

        switch entity {
        case .coin:
            node = scene.rootNode.childNode(withName: "coin", recursively: true) ?? node
            node.position = SCNVector3(0, -5, zPosition)

        case .brick:
            node = scene.rootNode.childNode(withName: "brick", recursively: true) ?? node
            node.position = SCNVector3(0, 0, zPosition)
        }

        self.sceneView.scene.rootNode.addChildNode(node)

        zPosition += delta
        count += 1
    }
}

It shows one coin and one brick at last positions.

I am new to scenekit so would be doing something wrong, Please help me.

Upvotes: 0

Views: 1024

Answers (1)

PongBongoSaurus
PongBongoSaurus

Reputation: 7385

Building on from the other comments and as @rmaddy has said an SCNNode has a clone() function (which is the approach you should take here) and which simply:

Creates a copy of the node and its children.

One thing to be aware of when using this however, is that each cloned Node will share the same geometry and materials.

That's to say that if you wanted at any point to have some bricks with a red colour and some with a green colour you wouldn't be able to do it with this method since:

changes to the objects attached to one node will affect other nodes that share the same attachments.

To achieve this e.g. to render two copies of a node using different materials, you must copy both the node and its geometry before assigning a new material, which you can read more about here: Apple Discussion

The reason you are only ever seeing one instance of either the coin or brick is because each time you are iterating through your loop you are saying that the newly created node is equal to either the coin or the brick, so naturally the last element in that loop will be the one that references that element from your scene.

Putting this into practice and solving your issue therefor, your setupWorld function should look like something like this:

/// Sets Up The Coins & Bricks
func setupworld(){

    //1. Get Our SCNScene
    guard let scene = SCNScene(named: "art.scnassets/MainScene.scn") else { return }

    //2. Store The ZPosition
    var zPosition =  -10

    //3. Store The Delta
    let delta = -4

    //4. Get The SCNNodes We Wish To Clone
    guard let validCoin = scene.rootNode.childNode(withName: "coin", recursively: true),
           let validBrick = scene.rootNode.childNode(withName: "brick", recursively: true) else { return }

    //5. Loop Through The Entity Array & Create Our Nodes Dynamically
    var count = 0

    for entity in entityArray {

        var node = SCNNode()

        switch entity{

        case .coin:
            //Clone The Coin Node
            node = validCoin.clone()
            node.position = SCNVector3(0, -5, zPosition)

        case .brick:
            //Clone The Brick Node
            node = validBrick.clone()
            node.position = SCNVector3(0, 0, zPosition)
        }

        //6. Add It To The Scene
        self.sceneView.scene.rootNode.addChildNode(node)

        //7. Adjust The zPosition
        zPosition += delta
        count += 1
    }

}

Upvotes: 3

Related Questions