0
votes

I've written a custom subclass of SKLabelNode which should apply a rudimental "drop shadow" to my label:

class ShadowLabel: SKLabelNode {
    var shadowNode: SKLabelNode

    init(fontNamed font: String = "Foo", text: String, size: CGFloat, zPosition zPos: CGFloat, shadowColor: SKColor = SKColor.black, shadowOffset: CGPoint = CGPoint(x: 0, y: -4), shadowAlpha: CGFloat = 0.5) {
        shadowNode = SKLabelNode(fontNamed: font)

        super.init(fontNamed: font)
        self.text = text
        self.fontSize = size
        self.zPosition = zPos

        shadowNode.text = self.text
        shadowNode.zPosition = self.zPosition - 1
        shadowNode.fontColor = shadowColor
        shadowNode.position = shadowOffset
        shadowNode.fontSize = self.fontSize
        shadowNode.alpha = 0.5

        self.addChild(shadowNode)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setNewText(_ newText: String) {
        self.text = newText
        self.shadowNode.text = newText
    }
}

My problem is, that at runtime, the console gives me the following error:

use of unimplemented initializer 'init()' for class 'MyProject.ShadowLabel'

I use the custom subclass in my GameScene class as following:

class GameScene: SKScene {
    var scoreLabel = (ShadowLabel(fontNamed: "Foo", text: "", size: 100, zPosition: 150, shadowColor: SKColor.black, shadowOffset: CGPoint(x: 0, y: -4), shadowAlpha: 0.5))

    override func didMove(to view: SKView) {
        scoreLabel.text = "\(gameScore.totalScore)" // a struct which counts the game score
        scoreLabel.color = SKColor.white
        scoreLabel.fontSize = 100
        scoreLabel.zPosition = 150
        scoreLabel.position = CGPoint(x: Scene.width/2, y: Scene.heigth - 40 - scoreLabel.frame.height)
        addChild(scoreLabel)
    }
}

I don't know why the parameter-empty init() call is made in the first place.

Any suggestion?

2

2 Answers

0
votes

You still need to use the parameterless init method.

override init() {
    shadowNode = SKLabelNode()
    super.init()
}

You'll have to set your shadowNode to equal something which will probably break the other stuff you've got going on.

I tend to store my nodes just in the child array of the node so I don't have to deal with stuff like this, not sure if it's best practise though.

0
votes

I've found a non-elegant workaround to solve my issue (the additional overlayNode is required because, by treating shadowNode as a child of the main label node, it overlays the main node no matter what zPosition you choose, so overlayNode "restores" the shadow effect):

class ShadowLabel: SKLabelNode {
    var shadowNode: SKLabelNode = SKLabelNode(fontNamed: "Foo")
    var overlayNode: SKLabelNode = SKLabelNode(fontNamed: "Foo")

    init(fontNamed font: String = "Foo", text: String, size: CGFloat, color: SKColor, zPosition zPos: CGFloat, shadowColor: SKColor = SKColor.black, shadowOffset: CGPoint = CGPoint(x: 0, y: -4), shadowAlpha: CGFloat = 0.5) {
        shadowNode = SKLabelNode(fontNamed: font)
        overlayNode = SKLabelNode(fontNamed: font)

        super.init(fontNamed: font)
        self.text = text
        self.fontSize = size
        self.zPosition = zPos
        self.fontColor = color

        shadowNode.text = self.text
        shadowNode.zPosition = self.zPosition - 1
        shadowNode.fontColor = shadowColor
        shadowNode.position = shadowOffset
        shadowNode.fontSize = self.fontSize
        shadowNode.alpha = 0.5

        self.addChild(shadowNode)

        overlayNode.text = self.text
        overlayNode.zPosition = self.zPosition + 1
        overlayNode.fontColor = self.fontColor
        overlayNode.position = self.position
        overlayNode.fontSize = self.fontSize

        self.addChild(overlayNode)
    }

    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setNewText(_ newText: String) {
        self.text = newText
        self.shadowNode.text = newText
        self.overlayNode.text = newText
    }
}