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.
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
}
}