0

I have an SKNode which contains 2 sub nodes (a sprite node w/an image and an SKLabelNode above the image which prints the number of available units).

Previously, after each time the USER 'spent' a unit the counters would update by removing the previous unit and adding a new one.

That was working, but obviously quite inefficient. Now I'm trying to grab the existing node and update its text like so...

        let newNode = createUnitCounter(type: type, nation: nation, count: countStr)
        if let existingNode = iterator.filter({ $0.name == newNode.name }).first?.children.filter({ $0 is SKLabelNode }).first as? SKLabelNode {
            existingNode.text = countStr
        } else {
            DispatchQueue.main.async { [weak self] in
                guard let self = self else { return }
                self.addChild(newNode)
            }
        }

Using breakpoints I can see that the node should be updating (it's text shows the proper values when I type po existingNode.text in the console), but the screen never shows the update. Other nodes I've refactored are updating on the screen, but not this one.

How do tell the node to redraw (e.g. something like existingNode.setNeedsDisplay())?

Here's how I create the node originally in createUnitCounter:type:nation:count ...

func createUnitCounter(type: UnitType, nation: Nation, count: String) -> SKNode {
    let node = SKNode()
    node.name = type.prefix + ElId.Nodes.counter

    let image = createCounterImage(mode: .offense, type: type, nation: nation)
    assignCounterPosition(to: image, of: type)
    node.addChild(image)
    
    let label = createCounterLabel(text: count, position: nil, type: type)
    label.verticalAlignmentMode = .bottom
    assignCounterPosition(to: label, of: type)
    node.addChild(label)
    
    return node
}

func createCounterLabel(text: String, position: CGPoint?, type: UnitType?) -> SKLabelNode {
    let node = SKLabelNode(fontNamed: Assets.font)
    node.text = text
    node.zPosition = Position.zUIElementH

    if type == selectedUnitType { node.fontColor = Colors.red }
    
    if let p = position { node.position = p }
    
    return node
}

func createCounterImage(mode: GameMode, type: UnitType = .infantry, nation: Nation = .usa) -> SKSpriteNode {
...
}
Mercutio
  • 1,152
  • 1
  • 14
  • 33
  • DispatchQueue -- so you're in a background thread here? can you say why? that might be your problem. ie try wrapping the text update just like you do the addchild cmd – Fault Jan 03 '23 at 14:51
  • The addChild works; the problem is in the other block of the condition (when the child node already exists instead of the else). I tried wrapping "existingNode.text = countStr" but that didn't work :( – Mercutio Jan 03 '23 at 17:45
  • Actually the problem seems to be the iterator. I recently switched all of my for loops to iterators and wrapped all the tree modifications in DQ.main calls to ensure they were serial because I was getting a mutated collection error somewhere. That fixed the previous bug, but it appears that when I copy the iterator it breaks the reference for the individual nodes (although when check identity '===' still says it's true...) – Mercutio Jan 03 '23 at 18:12

1 Answers1

0

So I isolated the issue to the fact that it was chaining the filters through an iterator which broke the node's reference. When I switched the iterator back out to the children array, everything was working. However that was going to create issues, so I found a similar method and for some reason I was able to keep the iterator and the references survived when accessing the same node independent of the iterator and then accessing that...

        let newNode = createUnitCounter(type: type, nation: nation, count: countStr)
        if let existingNode = children.makeIterator().filter({ $0.name == newNode.name }).first {
            for child in existingNode.children {
                if let label = child as? SKLabelNode { label.text = countStr }
            }
        } else {
            addChild(newNode)
        }
Mercutio
  • 1,152
  • 1
  • 14
  • 33