Subclassing
Subclassing SKSpriteNode
s makes it easy to have multiple classes of a similar sprite. One use case for this would be in a breakout-like game where there are multiple kinds of blocks that can do different things.
In this example we’ll start with a normal BlockNode
. Then, we’ll subclass it to create a new type of block called ExplosionNode
.
Block Node
The code for the original block node looks like this.
class BlockNode: SKSpriteNode {
var background: SKShapeNode?
convenience init(size: CGSize) {
self.init(texture: nil, color: .clear, size: size)
background = SKShapeNode(rectOf: size, cornerRadius: 5)
background!.fillColor = .darkGray
background!.strokeColor = .lightGray
addChild(background!)
}
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
super.init(texture: texture, color: color, size: size)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func endBlock() {
guard let scene = self.scene as? GameScene else { self.removeFromParent(); return }
removeFromParent()
}
}
This simple SKSpriteNode class creates a block with a grey background. It can be created using BlockNode(size: CGSize())
.
In the game when the ball touches the block, endBlock()
is called to remove the block.
Now that we have a normal block lets make another, more fun, block.
Explosion Block
We can easily subclass the BlockNode
by adding it to the class definition of ExplosionBlockNode
like so.
class ExplosionBlockNode: BlockNode {
...
}
Now lets override the init function that makes the block grey, and instead make it red.
convenience init(size: CGSize) {
self.init(texture: nil, color: .clear, size: size)
background = SKShapeNode(rectOf: size, cornerRadius: 5)
background!.fillColor = .red
background!.strokeColor = .darkGray
addChild(background!)
}
Now the block can be created using the same method as the normal block, except now using ExplosionBlockNode(size: CGSize())
. This initializer will create a red block instead of a grey one.
We can also change the endBlock()
function to being special for the explosion block by simply adding it to the ExplosionBlockNode
like this.
override public func endBlock() {
guard let scene = self.scene as? GameScene else { self.removeFromParent(); return }
let scoreLabel = SKLabelNode(text: "Boom")
scoreLabel.color = .red
scoreLabel.position = self.position
scoreLabel.fontSize = 24
scene.addChild(scoreLabel)
scoreLabel.run(.sequence([.group([.moveTo(y: self.position.y + 50, duration: 0.4), .fadeOut(withDuration: 0.3)]), .removeFromParent()]))
scene.addChild(field)
field.run(SKAction.sequence([SKAction.wait(forDuration: 0.05),SKAction.removeFromParent()]))
removeFromParent()
}
Now when we call the endBlock
method on the explosion block it’ll add a little label saying “Boom” that fades quickly and animates up.
The final explosion block code looks like this.
class ExplosionBlockNode: BlockNode {
convenience init(size: CGSize) {
self.init(texture: nil, color: .clear, size: size)
background = SKShapeNode(rectOf: size, cornerRadius: 5)
background!.fillColor = .red
background!.strokeColor = .darkGray
addChild(background!)
}
override public func endBlock() {
guard let scene = self.scene as? GameScene else { self.removeFromParent(); return }
let scoreLabel = SKLabelNode(text: "Boom")
scoreLabel.color = .red
scoreLabel.position = self.position
scoreLabel.fontSize = 24
scene.addChild(scoreLabel)
scoreLabel.run(.sequence([.group([.moveTo(y: self.position.y + 50, duration: 0.4), .fadeOut(withDuration: 0.3)]), .removeFromParent()]))
scene.addChild(field)
field.run(SKAction.sequence([SKAction.wait(forDuration: 0.05),SKAction.removeFromParent()]))
removeFromParent()
}
}