Creating a subclass of SKShapeNode
Try changing your initializer like this:
class ColorRectangle: SKShapeNode {
var width: CGFloat!
var height: CGFloat!
var rectColor: UIColor!
convenience init(rectOfSize: CGSize, colorOfRectangle rectColor: UIColor) {
self.init()
self.init(rectOfSize: rectOfSize)
self.rectColor = rectColor
self.fillColor = rectColor
self.strokeColor = rectColor
}
}
no designated init for SKShapeNode(circleOfRadius: radius)
how's this?
class Player: SKShapeNode {
init(circleOfRadius: CGFloat){
super.init()
let diameter = circleOfRadius * 2
self.path = CGPathCreateWithEllipseInRect(CGRect(origin: CGPointZero, size: CGSize(width: diameter, height: diameter)), nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Inherit SKShapeNode
SKShapeNode.init(circleOfRadius:)
is a convenience initializer on SKShapeNode
so you can't call it from a Swift initializer. Swift enforces the designated initializer pattern more strictly than Objective C does.
Unfortunately, it appears the designated initializer for SKShapeNode
is just init
, so you'll need to do something like this:
public class Player: SKShapeNode {
public var playerName : String
private var inventory: [enumObject]
init(nameOfPlayer:String, position:CGPoint, radius: CGFloat) {
playerName = nameOfPlayer
inventory = [enumObject]()
super.init()
self.path = CGPath(ellipseIn: CGRect(origin: .zero, size: CGSize(width: radius, height: radius)), transform: nil)
self.position = position
self.fillColor = SKColor.white
}
// init?(coder:) is the other designated initializer that we have to support
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The code above works for subclassing SKShapeNode
, but given the API that Apple provides and considering how your code might need to change in the future, it might make more sense to create an SKNode
subclass that contains one or more SKShapeNode
s. In this setup, if you wanted to represent the player as more than just a simple circle, you could simply add additional nodes to the player node.
Subclassing SKShapeNode with Swift
You have two problems with the code you tried:
rectOfSize
inSKShapeNode
takes aCGSize
not aCGPoint
rectOfSize
inSKShapeNode
is a convenience initializer so you won't be able to call it from a subclass. You will have to callsuper.init()
and implement the rect functionality yourself
You can do something like this:
init(rectOfSize: CGSize) {
super.init()
var rect = CGRect(origin: CGPointZero, size: rectOfSize)
self.path = CGPathCreateWithRect(rect, nil)
}
Why is my SKShapeNode subclass not appearing when I run my app?
I couldn't figure out a solution when the class inherits from an SKShapeNode
; however, I was able to figure out how to do it when it inherits from an SKNode
. All that is required is to initialize the SKNode
and then add an SKShapeNode
- with your desired attributes - as a child of the SKNode
like what is done below:
class FallingBlock: SKNode {
init(side: CGPoint) {
super.init()
self.addNewBlock(side)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
print("falling block reference deleted")
}
private func addNewBlock(_ side: CGPoint) {
var color = [UIColor.red,UIColor.cyan,UIColor.green,UIColor.yellow,UIColor.orange,UIColor.systemPink].randomElement() as! UIColor
let obstacle = SKShapeNode(rectOf: CGSize(width: 20, height: 20), cornerRadius: 3)
obstacle.fillColor = color
obstacle.strokeColor = color
obstacle.position = side
obstacle.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 20, height: 20))
obstacle.physicsBody?.affectedByGravity = true
obstacle.zPosition = 1
obstacle.physicsBody?.categoryBitMask = PhysicsCategories.obstacleCategory
obstacle.name = ObjectNames.obstacle
self.addChild(obstacle)
}
}
why cant use subclass of SKShapenode?
You are not properly subclassing, You are using your Enemy object as both a factory and an instance, separate the 2.
Factory:
public class EnemyFactory
{
public func createEnemy(color: SKColor, radius: CGFloat, position: CGPoint) -> Enemy{
let enemy = Enemy(circleOfRadius: radius)
enemy.setup(color:color, radius: radius, position: position)
return enemy
}
}
Instance Class:
public class Enemy: SKShapeNode {
static let Factory = EnemyFactory()
public var health: Int = 5
func setup (color: SKColor, radius: CGFloat, position: CGPoint) {
self.position = position
fillColor = color
glowWidth = 0.5
self.health = 5
strokeColor = color
let physicsBody = SKPhysicsBody(circleOfRadius: radius)
physicsBody.affectedByGravity = false
physicsBody.isDynamic = true
physicsBody.collisionBitMask = GameScene.bodyType.player.rawValue
physicsBody.categoryBitMask = GameScene.bodyType.enemy.rawValue
physicsBody.contactTestBitMask = GameScene.bodyType.player.rawValue
physicsBody.usesPreciseCollisionDetection = true
self.physicsBody = physicsBody
}
override init(){
super.init()
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Some liberties I took: I removed local redundant variables like color and scene, you can grab these straight from the object, no need to have another variable to save them. You also do not need getters and setters, Swift does this for you already.
Setting non-optional properties in an SKShapeNode subclass
You can not call the method addChild
before calling the super.init
so here is the fix,
class MyNode: SKShapeNode {
private var label: SKLabelNode
init(_ frame: CGRect) {
self.label = SKLabelNode(text: "Some text")
super.init()
self.path = CGPath.init(rect: frame, transform: nil)
self.addChild(self.label)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Related Topics
Diffrence Between Function and Generic Function in Swift
Scenekit Shape Between 4 Points
Swift For-In Loop with Enumerate on Custom Array2D Class
Displaying State of an Async API Call in Swiftui
Sending Firebase Push Notifications to Logged-In Users Only
Difficulties to Assign Default Value to a Parameter of a Function
Swift: Cast Any Object to Int64 = Nil
Swift Variable Declaration and Initialize
Limiting Concurrent Access to a Service Class with Rxswift
Nscollectionviewitem Never Instantiate
Why Does Realm Use Realmoptional<Int> Rather Than Int? for Optional Properties
Http Request Swift Providing Parameters
Swift: Generic Overloads, Definition of "More Specialized"
Swift, for Some Uiviews to Their Overall Controller When Clicked
Retrieving an Array from Firebase
Swift Generics Error: Cannot Convert Value of Type 'Type<T>' to Expected Argument Type 'Type<_>'